Script for incrementally creating records - sql-server

Paul provided a useful script for the issue below but I would like to actually effect the changes. I can only see it if I use the select statement
Please help with this one
Table name: Citizen
Firstname Lastname Telephone Many other columns......
John Smith 03907625212
Andrew Evans 0807452132
Bill Towny 05907122139
Dame Beaut 07894650569
I have over 150,000 records where the Telephone number needs to be adopted to a set format (set telephone area code and in incremental order) ie 01907000001, 01907000002 as shown below. There are other columns asides the firstname and lastname which will all remain unchanged..only telephone field requires this transformation.
It should ideally look like this:
Firstname Lastname Telephone Many other columns......
John Smith 01907000001
Andrew Evans 01907000002
Bill Towny 01907000003
Dame Beaut 01907000004
I will really appreciate some help or guidance on this.

Try something like this:
SELECT
[FirstName],
[LastName],
'01907' + --area code
RIGHT('00000' + --middle padding for zero's
CAST(ROW_NUMBER() OVER (ORDER BY [LastName]) AS VARCHAR) --incremental value
,6) AS 'Telephone' --6 characters plus area code
--<< YOUR OTHER FIELDS
FROM
[AdventureWorks].[Person].[Person]
I used Adventure Works just to test it.
Change the ORDER BY clause in the windowing function if you want it to increment by something else.

Related

how to separate and show data from one column?

I have a problem splitting single column values to multiple column values.
On this:
Name
------------
Tom Howard
Michael Black
Wiliam Cruise
Bet Moor
I need the output something like this:
first_name last_name
------------------------------
Tom Howard
Michael Black
Wiliam Cruise
Bet Moor
I have to show data(last_name) from one column(name).
Thank you
Depending on your version, you could use PARSENAME() or Substring()
Declare #YourTable table (Name varchar(50))
Insert into #YourTable values
('Tom Howard'),
('Michael Black'),
('Wiliam Cruise'),
('Bet Moor')
Select Name
,first_name=PARSENAME(Replace(Name,' ','.'),2)
,last_name =PARSENAME(Replace(Name,' ','.'),1)
From #YourTable
-- OR --
Select Name
,first_name=Substring(Name,1,charindex(' ',name)-1)
,last_name =Substring(Name,charindex(' ',name)+1,50)
From #YourTable
Returns
You can use the left and right function to find these items pretty quickly:
select Name, left(Name,charindex(' ',Name)-1) as first_name, right(Name,charindex(' ',Name)-1) as last_name from yourtable
As long as you have a single space in the Name field this should work fine, if you have more than one space then you will lose any data that is between the spaces.

Inconsistent data in table

A partner where I work have created the customer table with the following fields:
first_name, middle_name, last_name, second_last_name, full_name
Where full_name is the concatenation of the other fields.
Can you give me the best explaining why is a bad practice?
It's not ideal because sooner or later, someone or something is going to update last_name or first_name without updating full_name, or vice versa, and you'll have something like this in your database:
first_name last_name full_name
John White John Black
And then you get to try to figure out where the discrepancy is coming from and what this guy's last name is really supposed to be, which is no fun. If you're going to denormalize a table like this, there ought to be some compelling reason for doing so. What's your partner's rationale for wanting full_name to be a separate field?
You should probably investigate alternatives. For instance, you could define a view that returns the various name components from your table and also assembles them into a full_name. Depending on your RDBMS, you may have other options as well. For instance, in SQL Server you can put a computed column right into your table.
declare #customer table (first_name varchar(50), last_name varchar(50), full_name as first_name + ' ' + last_name);
insert #customer values ('John', 'B');
select * from #customer;
Result:
first_name last_name full_name
John B John B
If the full_name is persisted on storage, then you got data doubling: you waste twice the storage with no benefits and extra overhead on editing or other maintenance.
If full_name column is actually a function (e.g. it is calculated from the other elements on this row) the solution is fine!
Depending on the database engine you use those calculated columns can only be read (you have to update the other columns to change their outcome), or even be read-write. Writing to such a column is handled by another function, which for example could parse the full name and store the parts in the row, which is to be updated.

Order by parent-child relation "ItemCode"-"ItemReplacementCode" in one table

Let's suppose we have records of product with columns ItemCode and ItemReplacementCode.
Since we are talking about one table:
ItemCode is not a primary key
ItemReplacementCode isn't foreign key.
They are just simply varchars columns.
What I would like to see in select result is:
id, productname, itemcode, replacementCode
99, dell ###, a1234X, null
10034, dell ###, 1233bX, a1234X
10024, dell ###, 1232X, 1233bX
95, dell ###, 999ws, null
96, sony ###, 327b, null
and so on. Please note that itemCode and replacementCode aren't alphabetically friendly for sorting.
Can you guide me how to select products so they will be grouped and ordered by replacement code (please note, not grouped by scalar).
Certainly we are talking about kind of building graph of "relatives" retrieved by one sql statement among with "orphan" products which have no replacement.
Don't hesitate to ask for clarification.
References to similar discussions are appreciated.
I'm open to add additional hibernate relations only if they will not harm performance.
I am not 100% sure of what you are looking for, but here are some options.
To just order by replacement code
SELECT id, productname, itemcode, replacementCode
FROM ItemTable
ORDER BY replacementCode
I see that you have NULL values in the replacement code. If you want to order by the Item, but use the replacement code if there is one try this
SELECT ISNULL(replacementCode ,itemcode) AS NewItemCode ,id, productname
FROM ItemTable
ORDER BY ISNULL(replacementCode ,itemcode)

SQL Query that can return intersecting data

I have a hard time finding a good question title - let me just show you what I have and what the desired outcome is. I hope this can be done in SQL (I have SQL Server 2008).
1) I have a table called Contacts and in that table I have fields like these:
FirstName, LastName, CompanyName
2) Some demo data:
FirstName LastName CompanyName
John Smith Smith Corp
Paul Wade
Marc Andrews Microsoft
Bill Gates Microsoft
Steve Gibbs Smith Corp
Diane Rowe ABC Inc.
3) I want to get an intersecting list of people and companies, but companies only once. This would look like this:
Name
ABC Inc.
Bill Gates
Diane Rowe
John Smith
Marc Andrews
Microsoft
Smith Corp
Steve Gibbs
Paul Wade
Can I do this with SQL? How?
You take all the person names, and then also add all the companies
SELECT CONCAT([First Name],' ',[Last Name]) AS Name FROM Contacts
UNION ALL
SELECT DISTINCT CompanyName FROM Contacts
WHERE CompanyName IS NOT NULL
The DISTINCT keyword ensures that companies are output only once, and the WHERE
clause removes rows where no company info is known.
If a person has the same name as a company, then this will output a duplicate. If you don't want that, then change UNION ALL to UNION, and any name will be output only once.
I'm not sure what you mean by "intersecting," but you can easily get the results you describe as the union of two queries against that same table.
select
t.firstname + ' ' + t.lastname
from
mytable t
union
select
t.company
from
mytable t
Edit: UNION should make each SELECT distinct by default.
Does this do what you need?
SELECT FirstName + ' ' + LastName AS Name
FROM Contacts
UNION
SELECT CompanyName
FROM Contacts
(The UNION rather than UNION ALL will ensure distinctness of both top and bottom parts. mdma's answer will work if you do need the possibility of duplicate people names. You might need to add an ORDER BY Name depending on your needs)

SQL Server Full Text Searching

I'm currently working on an application where we have a SQL-Server database and I need to get a full text search working that allows us to search people's names.
Currently the user can enter a into a name field that searches 3 different varchar cols. First, Last, Middle names
So say I have 3 rows with the following info.
1 - Phillip - J - Fry
2 - Amy - NULL - Wong
3 - Leo - NULL - Wong
If the user enters a name such as 'Fry' it will return row 1. However if they enter Phillip Fry, or Fr, or Phil they get nothing.. and I don't understand why its doing this. If they search for Wong they get rows 2 and 3 if they search for Amy Wong they again get nothing.
Currently the query is using CONTAINSTABLE but I have switched that with FREETEXTTABLE, CONTAINS, and FREETEXT without any noticeable differences in the results. The table methods are be preferred because they return the same results but with ranking.
Here is the query.
....
#Name nvarchar(100),
....
--""s added to prevent crash if searching on more then one word.
DECLARE #SearchString varchar(100)
SET #SearchString = '"'+#Name+'"'
SELECT Per.Lastname, Per.Firstname, Per.MiddleName
FROM Person as Per
INNER JOIN CONTAINSTABLE(Person, (LastName, Firstname, MiddleName), #SearchString)
AS KEYTBL
ON Per.Person_ID = KEYTBL.[KEY]
WHERE KEY_TBL.RANK > 2
ORDER BY KEYTBL.RANK DESC;
....
Any Ideas...? Why this full text search is not working correctly ?
If you're just searching people's names, it might be in your best interest to not even use the full text index. Full text index makes sense when you have large text fields, but if you're mostly dealing with one word per field, I'm not sure how much extra you would get out of full text indexes. Waiting for the full text index to reindex itself before you can search for new records can be one of the many problems.
You could just make a query such as the following. Split your searchstring on spaces, and create a list of the search terms.
Select FirstName,MiddleName,LastName
From person
WHERE
Firstname like #searchterm1 + '%'
or MiddleName like #searchterm1 + '%'
or LastName like #searchterm1 + '%'
or Firstname like #searchterm2 + '%'
etc....
FreeTextTable should work.
INNER JOIN FREETEXTTABLE(Person, (LastName, Firstname, MiddleName), #SearchString)
#SearchString should contain the values like 'Phillip Fry' (one long string containing all of the lookup strings separated by spaces).
If you would like to search for Fr or Phil, you should use asterisk: Phil* and Fr*
'Phil' is looking for exactly the word 'Phil'. 'Phil*' is looking for every word which is starting with 'Phil'
Thanks for the responses guys I finally was able to get it to work. With part of both Biri, and Kibbee's answers. I needed to add * to the string and break it up on spaces in order to work. So in the end I got
....
#Name nvarchar(100),
....
--""s added to prevent crash if searching on more then one word.
DECLARE #SearchString varchar(100)
--Added this line
SET #SearchString = REPLACE(#Name, ' ', '*" OR "*')
SET #SearchString = '"*'+#SearchString+'*"'
SELECT Per.Lastname, Per.Firstname, Per.MiddleName
FROM Person as Per
INNER JOIN CONTAINSTABLE(Person, (LastName, Firstname, MiddleName), #SearchString)
AS KEYTBL
ON Per.Person_ID = KEYTBL.[KEY]
WHERE KEY_TBL.RANK > 2
ORDER BY KEYTBL.RANK DESC;
....
There are more fields being searched upon I just simplified it for the question, sorry about that, I didn't think it would effect the answer. It actually searches a column that has a csv of nicknames and a notes column as well.
Thanks for the help.
Another approach could be to abstract the searching away from the individual fields.
In other words create a view on your data which turns all the split fields like firstname lastname into concatenated fields i.e. full_name
Then search on the view. This would likely make the search query simpler.
You might want to check out Lucene.net as an alternative to Full Text.

Resources