how to separate and show data from one column? - sql-server

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.

Related

Change wrong french characters on table

For some reason we found on the database characters like this: Ã
I can assume this character represent the character: é
Now I need to revise the whole table but checking all other characters to make sure there are no others.
Where I can find the relation of characters for example between this à and é? or probably find an SQL function that is already done to make those replacement.
I'm using SQL Server 2014
As mentioned by Daniel E, your dirty data might have been caused by the use of incorrect code pages (UTF-8 that was interpreted as ISO 8859-1).
One way to find entries with dirty data, is to use a "not exists" ("^") like expression with the list of valid characters in that expression. See example below.
declare #t table (name varchar(20))
insert into #t values ('touché')
insert into #t values ('encore touché')
insert into #t values ('reçu')
insert into #t values ('hello world')
select * from #t where name like '%[^a-zA-Z., -]%'
select * from #t where name like '%[^a-zA-Z.,èêé -]%' COLLATE Latin1_General_BIN

split a column in two and sort in mssql

I'm new to sql and i need to do this
in MSSQL:
I have a simple tble with userid, fullname,age and so on
where fullname is obviously firstname lastname like 'Adam Smith'
I need to sort the table according to surname only. Is there anyway?
If there's only 1 lastname then you could use the PARSENAME trick.
It's a function that's normally used to get a specified part from an object name.
For example to get '[mytable]' from '[myschema].[mydatabase].[mytable]'.
So it splits the string by the dot.
Your string has spaces.
When the spaces are replaced by dot, then it's easy to get the first element from the right via PARSENAME.
SELECT *
FROM yourtable
ORDER BY parsename(replace(fullname,' ','.'),1)
But do note that PARSENAME returns NULL when there's more than 4 elements.
You can use right with charindex and reverse to get the part of the string after the last space, like this:
First, create and populate sample table(Please save us this step in your future questions):
DECLARE #T AS TABLE
(
FullName nvarchar(100)
)
INSERT INTO #T(FullName) VALUES
(N'Zohar Peled'),
(N'Amir Shahbabaie'),
(N'Madona'),
(N'Gabriel José de la Concordia García Márquez')
The query:
SELECT *
FROM #T
ORDER BY RIGHT(FullName, CHARINDEX(' ',REVERSE(FullName)))
Results:
FullName
Madona
Gabriel José de la Concordia García Márquez
Zohar Peled
Amir Shahbabaie
As you can see, this will also work if your strings are not what you expect (and when dealing with names, they rarely are what you expect)

Script for incrementally creating records

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.

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.

T-SQL for Updating Rows with same value in a column

I have a table lets say called FavoriteFruits that has NAME, FRUIT, and GUID for columns. The table is already populated with names and fruits. So lets say:
NAME FRUIT GUID
John Apple NULL
John Orange NULL
John Grapes NULL
Peter Canteloupe NULL
Peter Grapefruit NULL
Ok, now I want to update the GUID column with a new GUID (using NEWID()), but I want to have the same GUID per distinct name. So I want all the John Smiths to have the same GUID, and I want both the Peters to have the same GUID, but that GUID different than the one used for the Johns. So now it would look something like this:
NAME FRUIT GUID
John Apple f6172268-78b7-4c2b-8cd7-7a5ca20f6a01
John Orange f6172268-78b7-4c2b-8cd7-7a5ca20f6a01
John Grapes f6172268-78b7-4c2b-8cd7-7a5ca20f6a01
Peter Canteloupe e3b1851c-1927-491a-803e-6b3bce9bf223
Peter Grapefruit e3b1851c-1927-491a-803e-6b3bce9bf223
Can I do that in an update statement without having to use a cursor? If so can you please give an example?
Thanks guys...
Update a CTE won't work because it'll evaluate per row. A table variable would work:
You should be able to use a table variable as a source from which to update the data. This is untested, but it'll look something like:
DECLARE #n TABLE (Name varchar(10), Guid uniqueidentifier);
INSERT #n
SELECT Name, newid() AS Guid
FROM FavoriteFruits
GROUP BY Name;
UPDATE f
SET f.Guid = n.Guid
FROM #n n
JOIN FavoriteFruits f ON f.Name = n.Name
So that populates a variable with a GUID per name, then joins it back to the original table and updates accordingly.
To clarify comments re a table expression in the USING clause of a MERGE statement.
The following won't work because it'll evaluate per row:
MERGE INTO FavoriteFruits
USING (
SELECT NAME, NEWID() AS GUID
FROM FavoriteFruits
GROUP
BY NAME
) AS source
ON source.NAME = FavoriteFruits.NAME
WHEN MATCHED THEN
UPDATE
SET GUID = source.GUID;
But the following, using a table variable, will work:
DECLARE #n TABLE
(
NAME VARCHAR(10) NOT NULL UNIQUE,
GUID UNIQUEIDENTIFIER NOT NULL UNIQUE
);
INSERT INTO #n (NAME, GUID)
SELECT NAME, NEWID()
FROM FavoriteFruits
GROUP
BY NAME;
MERGE INTO FavoriteFruits
USING #n AS source
ON source.NAME = FavoriteFruits.NAME
WHEN MATCHED THEN
UPDATE
SET GUID = source.GUID;
There's a single-statement solution too, which, however, has some limitations. The idea is to use OPENQUERY(), like this:
UPDATE FavoriteFruits
SET GUID = n.GUID
FROM (
SELECT NAME, GUID
FROM OPENQUERY(
linkedserver,
'SELECT NAME, NEWID() AS GUID FROM database.schema.FavoriteFruits GROUP BY NAME'
)
) n
WHERE FavoriteFruits.NAME = n.NAME
This solution implies that you need to create a self-pointing linked server. Another specificity is that you can't use this method on table variables nor local temporary tables (global ones would do as well as 'normal' tables).

Resources