If I have a table with a column that contains fullnames such as:
fullname
------------
Joe Bloggs
Peter Smith
Mary Jones and Liz Stone
How can I retrieve the first and last name from each of the entries in the full name column using SQL. I'm not worried about the second name in the 3rd entry in my example i.e. Liz Stone.
So basically to retrieve
Firstname
---------
Joe
Peter
Mary
Lastname
--------
Bloggs
Smith
Jones
Here is a pre SQL Server 2016 method, which uses basic string functions to isolate the first and last names.
SELECT SUBSTRING(fullname, 1, CHARINDEX(' ', fullname) - 1) AS Firstname,
SUBSTRING(fullname,
CHARINDEX(' ', fullname) + 1,
LEN(fullname) - CHARINDEX(' ', fullname)) AS Lastname
FROM yourTable
Note that this solution assumes that the fullname column only contains a single first name and a single last name (i.e. no middle names, initials, etc.).
This is a slippery slope and there are no easy answers. That said, consider the following
Declare #YourTable table (FullName varchar(50))
Insert Into #YourTable values
('Joe Bloggs'),
('Peter Smith'),
('Betty Jane Martinez'),
('Mary Jones and Liz Stone')
Select A.*
,FirstName = Pos1+case when Pos3 is not null then ' '+Pos2 else '' end
,LastName = case when Pos3 is null then Pos2 else Pos3 end
From #YourTable A
Cross Apply (
Select Pos1 = xDim.value('/x[1]','varchar(max)')
,Pos2 = xDim.value('/x[2]','varchar(max)')
,Pos3 = xDim.value('/x[3]','varchar(max)')
,Pos4 = xDim.value('/x[4]','varchar(max)')
,Pos5 = xDim.value('/x[5]','varchar(max)')
,Pos6 = xDim.value('/x[6]','varchar(max)')
From (Select Cast('<x>' + replace((Select substring(FullName,1,charindex(' and ',FullName+' and ')-1) as [*] For XML Path('')),' ','</x><x>')+'</x>' as xml) as xDim) as A
) B
Returns
FullName FirstName LastName
Joe Bloggs Joe Bloggs
Peter Smith Peter Smith
Betty Jane Martinez Betty Jane Martinez
Mary Jones and Liz Stone Mary Jones
If it helps with the visual, the CROSS APPLY generates
SELECT CASE
WHEN CHARINDEX(' ', FullName) > 0
THEN SUBSTRING(FullName, 1, LEN(FullName) - CHARINDEX(' ', REVERSE(FullName)))
ELSE ''
END AS FirstName,
CASE
WHEN CHARINDEX(' ', FullName) > 0
THEN REVERSE(SUBSTRING(REVERSE(FullName),
1,
CHARINDEX(' ', REVERSE(FullName)) - 1))
ELSE FullName
END AS LastName
FROM(VALUES('Mary Anne Bloggs'), ('Joe Bloggs'), ('Bloggs')) AS T(FullName);
This version checks that there is a space in the full name to split on. If there isn't then the first name is set to an empty string and the full name is put into the surname. Also, reverse is employed to split on the last space when there is more than one space
I use this query to retrieve first and lastname
SELECT
SUBSTRING(FULLNAME, 1, CASE WHEN CHARINDEX(' ', FULLNAME)>0 THEN CHARINDEX(' ', FULLNAME) - 1 ELSE LEN(FULLNAME) END ) AS Firstname,
REVERSE(SUBSTRING(REVERSE(FULLNAME), 1, CASE WHEN CHARINDEX(' ', REVERSE(FULLNAME))>0 THEN CHARINDEX(' ', REVERSE(FULLNAME)) - 1 ELSE LEN(REVERSE(FULLNAME)) END ) ) AS Firstname
FROM HRMDESFO.EMPLOID
Results
BigQuery: Standard SQL
substr(name,1,STRPOS(name,' ')-1) as FirstName,
substr(name,STRPOS(name,' ')+1,length(name)) as LastName
This is the easiest and shortest to this question without any assumptions. Also you can even further enhance this with a rtrim(ltrim('firstname lastname')).
Just in case of any spaces before the strings,
Select
substring('Firstname Lastname',1,CHARINDEX(' ', 'Firstname Lastname')) as firstname,
substring('Firstname Lastname',CHARINDEX(' ', 'Firstname Lastname'),LEN('Firstname Lastname')) as Lastname
select passemail,substring(passemail,1,instr(passemail,'#') - 1) as name ,
substring(passemail,instr(passemail,'#') + 1,length(passemail)) from passenger
For getting firstName
SELECT SUBSTR(FULLNAME,1,(LOCATE(' ',FULLNAME))) AS FIRSTTNAME from EmployeeDetails;
FOR LASTNAME
SELECT SUBSTR(FULLNAME,(LOCATE(' ',FULLNAME))) AS LASTNAME from EmployeeDetails;
SO
SELECT SUBSTR(FULLNAME,1,(LOCATE(' ',FULLNAME))) AS FIRSTTNAME, SUBSTR(FULLNAME,(LOCATE(' ',FULLNAME))) AS LASTNAME from EmployeeDetails;
SELECT
LEFT(column_name, POSITION(' ' IN column_name)-1) AS first_name,
RIGHT(column_name, LENGTH(column_name) - POSITION(' ' IN column_name)) AS last_name
FROM table_name
SELECT SUBSTRING(candidate_name, 1, CASE WHEN CHARINDEX(' ', candidate_name)>0 THEN CHARINDEX(' ', candidate_name) - 1
ELSE LEN(candidate_name) END ) AS Firstname,
SUBSTRING(substring(candidate_name,CHARINDEX(' ', candidate_name)+1,LEN(candidate_name)), 1,
CASE WHEN CHARINDEX(' ', candidate_name)>1 THEN CHARINDEX(' ', substring(candidate_name,CHARINDEX(' ', candidate_name)+1,LEN(candidate_name)))
ELSE null END ) AS middle_name,
REVERSE(SUBSTRING(REVERSE(candidate_name), 1,
CASE WHEN CHARINDEX(' ', REVERSE(candidate_name))>0
THEN CHARINDEX(' ', REVERSE(candidate_name)) - 1
ELSE null END ) )AS last_name
FROM Test_name
So first we have to find the index for space(" ") because space is the character which is separating the two words ( first_name+" "+last_name).
In my case, its mid_index is a variable that stores the index for space(" ").
SELECT primary_poc, STRPOS(fullname,' ') AS "mid_index"
FROM yourTable_name
*Now we will use min_index to find the left and right sides of words. For this, we can use a subquery.
Below is the final query *
SELECT fullname,
LEFT(fullname, mid_index - 1) AS "first_name",
RIGHT(fullname, LENGTH(primary_poc) - mid_index) AS "last_name"
FROM
(
SELECT primary_poc, STRPOS(fullname,' ') AS "mid_index"
FROM yourTable_name
) AS t1
SELECT
SUBSTR(NAME,1,(LOCATE(NAME, ' '))) AS FIRSTTNAME
, SUBSTR(NAME,(LOCATE(NAME, ' ')+1)) AS LASTNAME
FROM yourTABLE;
FOR SQL SERVER
SELECT
SUBSTRING(fullname, 0, CHARINDEX(' ', fullname)) AS FirstName
,SUBSTRING(fullname, CHARINDEX(' ', fullname), LEN(fullname)) AS LastName
FROM [YourTable]
If your full name has another delimiter aside from space, such as dashes, you substitute in the dash e.g
SELECT
SUBSTRING(fullname, 0, CHARINDEX('-', fullname)) AS FirstName
,SUBSTRING(fullname, CHARINDEX('-', fullname), LEN(fullname)) AS LastName
FROM [YourTable]
In Postgres SQL
SELECT fullname,
SUBSTRING(fullname, 1, POSITION(' ' IN fullname) - 1) as first_name ,
SUBSTRING(fullname,(position(' 'in fullname))) AS lastname from details;
You can use,
STRING_SPLIT (string , separator)
Related
I have a ClientID formatted as a link to the file, it looks like:
Doe, John (W21135446).
I need to separate out this to be:
Last Name First Name File Number
Doe John W2135446
Including removing the () around the file number. How do I write the T-SQL code to do this for me?
I was able to achieve this using the CHARINDEX() and some string-manipulating system functions.
SELECT val.ClientID,
LTRIM(RTRIM(LEFT(ClientID, CHARINDEX(',', ClientID)-1))) AS LastName,
LTRIM(RTRIM(SUBSTRING(ClientID, CHARINDEX(',', ClientID) + 2, CHARINDEX('(', val.ClientID) - (CHARINDEX(',', ClientID)+2)))) AS FirstName,
LTRIM(RTRIM(SUBSTRING(ClientID, CHARINDEX('(', ClientID)+1, (CHARINDEX(')', val.ClientID) - CHARINDEX('(', ClientID)-1)))) AS FileNumber
FROM (VALUES ('Doe, John (W21135446)')) AS val (ClientID);
There are some notable caveats that always accompany working with strings like this: any name value with a comma (something like "Jones, Jr") will break, same with unexpected positions of the characters "(" and ")". So long as all of your data matches this exact pattern, this should help you get the job done.
I used the LTRIM() and RTRIM() functions to remove any leading or trailing spaces because I don't entirely trust my string-math, but they're not required so long as you verify your starting and ending points. Also, pay close attention to the arithmetic groupings and order of operations.
Output:
ClientID
LastName
FirstName
FileNumber
Doe, John (W21135446)
Doe
John
W21135446
There are a few ways to tackle this depending on what version of SQL Server you are on. Each of these:
DECLARE #string VARCHAR(1000) = 'Doe, John (W21135446).'
--==== 1. CHARINDEX + APPLY
SELECT
ClientId = #string,
LastName = SUBSTRING(#string, i1.Pos+1, i2.Pos-i1.Pos-1),
FirstName = SUBSTRING(#string, 0, i1.Pos),
FileNumer = SUBSTRING(#string, i2.Pos+1, i1.ln-i2.Pos-2)
FROM (VALUES(CHARINDEX(',',#string),LEN(#string))) AS i1(Pos,Ln)
CROSS APPLY (VALUES(CHARINDEX('(',#string,i1.Pos))) AS i2(Pos);
--==== 2. DELIMITEDSPLIT8K + CROSS TAB APPLY
SELECT
ClientId = #string,
LastName = MAX(CASE s.ItemNumber WHEN 1 THEN TRIM(',() .' FROM s.item) END),
FirstName = MAX(CASE s.ItemNumber WHEN 2 THEN TRIM(',() .' FROM s.item) END),
FileNumber = MAX(CASE s.ItemNumber WHEN 3 THEN TRIM(',() .' FROM s.item) END)
FROM dbo.DelimitedSplit8K(#string,' ') AS s;
Both Return:
ClientId LastName FirstName FileNumer
----------------------- ----------- ---------- -----------
Doe, John (W21135446). John Doe W21135446
Against a table:
--==== Sample Data
DECLARE #strings TABLE (ClientID VARCHAR(100));
INSERT #strings VALUES('Doe, John (W21135446).'),('Smith, Fred (X21139999).'),
('White, Walter (BCH20XD0).'),('Black, Jack (998877).')
--==== 1. CHARINDEX + APPLY
SELECT itvf_extract.*
FROM #strings AS s
CROSS APPLY
(
SELECT
ClientId = s.ClientID,
LastName = TRIM(SUBSTRING(s.ClientID, i1.Pos+1, i2.Pos-i1.Pos-1)),
FirstName = TRIM(SUBSTRING(s.ClientID, 0, i1.Pos)),
FileNumber = SUBSTRING(s.ClientID, i2.Pos+1, i1.ln-i2.Pos-2)
FROM (VALUES(CHARINDEX(',',s.ClientID), LEN(s.ClientID))) AS i1(Pos,Ln)
CROSS APPLY (VALUES(CHARINDEX('(',s.ClientID, i1.Pos))) AS i2(Pos)
) AS itvf_extract;
--==== 2. DELIMITEDSPLIT8K + CROSS TAB APPLY
SELECT
ClientId = s.ClientID,
LastName = MAX(CASE sp.ItemNumber WHEN 1 THEN TRIM(',() .' FROM sp.item) END),
FirstName = MAX(CASE sp.ItemNumber WHEN 2 THEN TRIM(',() .' FROM sp.item) END),
FileNumber = MAX(CASE sp.ItemNumber WHEN 3 THEN TRIM(',() .' FROM sp.item) END)
FROM #strings AS s
CROSS APPLY dbo.DelimitedSplit8K(s.ClientID,' ') AS sp
GROUP BY s.ClientID;
Both Return:
ClientId LastName FirstName FileNumber
-------------------------- --------- ---------- -----------
Doe, John (W21135446). John Doe W21135446
Smith, Fred (X21139999). Fred Smith X21139999
White, Walter (BCH20XD0). Walter White BCH20XD0
Black, Jack (998877). Jack Black 998877
have a play.....reasonably flexible for up to a 4 part split
CREATE TABLE #yourtable(
reference VARCHAR(50) NOT NULL PRIMARY KEY
);
INSERT INTO #yourtable(reference) VALUES
('Doe, John (W21135446)'),
('(Doe), John [W21135446]'),
('Jones [Bill] (W2)'),
('{Smith}, Fred, 684664')
;
WITH CTE AS (
SELECT reference,
REPLACE(
TRIM(REPLACE(TRANSLATE(reference,'()|[]{},',REPLICATE('*',8)),'*','')) ,' ','.' )AS extracted
FROM #yourtable
)
SELECT
reference,
PARSENAME(extracted,3) as Lastname,
PARSENAME(extracted,2) as Firstname,
PARSENAME(extracted,1) as FileNo
FROM CTE
drop table #yourtable
Columns:
FirstName
MiddleName
LastName
I want to automatically concatenate into a 4th column called 'FullName' separated by spaces Every time data is entered or changed in one of the above 3 columns the 'FullName' column is updated.
Sample Data
giving a mysql answer since you left a mysql tag:
In MySQL you can create a generated column, using the CONCAT_WS function.
Postgres doesn't support( as of Version 11 ) a Virtual column / derived column.
You may create a View instead.
CREATE OR replace VIEW v_names
AS
SELECT firstname,
middlename,
lastname,
firstname
||CASE
WHEN nullif(middlename, '') IS NULL THEN ''
ELSE ' '
||middlename
END
||CASE
WHEN nullif(lastname, '') IS NULL THEN ''
ELSE ' '
||lastname
END AS FullName
FROM names;
knayak=# INSERT INTO names(FirstName,MiddleName,LastName) VALUES ( 'John', 'Maynard','Keynes');
INSERT 0 1
knayak=# INSERT INTO names(FirstName,MiddleName,LastName) VALUES ( 'John','','Doe');
INSERT 0 1
knayak=# select * from v_names;
firstname | middlename | lastname | fullname
-----------+------------+----------+---------------------
John | Maynard | Keynes | John Maynard Keynes
John | | Doe | John Doe
I have two tables, one contains a list of employees, the other contains a list of PO's.
The PO Table looks like:
PoID PO# Name City State
1 55 Jasons Company Miami FL
2 66 Mikes Company NewYork NY
3 77 Sallys Company Dallas TX
My Employees Table looks like:
EmployeeID Name Phone Email PoID
1 John 123-123-1233 j#j.com 1
2 Alex 234-234-2344 a#a.com 1
3 Cindy 345-345-3455 c#c.com 2
4 Jessica 356-356-3566 j#j.com 3
Now if my SQL Select statement is this:
SELECT * FROM PO p
LEFT JOIN Employees e
ON p.PoID = e.PoID
It will return all records in my PO table and perhaps just the top entry of any employee associated with that record. I need the Names/Emails of all records associated to be pulled as well.
I'm not sure how I can accomplish this as I do not want duplicate PO entries but rather just a comma delimited list of any possible names/emails associated with that PO to pull up in two additional columns on my PO.
Hope it makes sense, if anyone has come across this your insight is appreciated.
You can try this query
SELECT p.*,
STUFF((SELECT DISTINCT ',' + Name
FROM #Employees e1
WHERE e1.PoID = p.PoID
FOR XML PATH (''))
, 1, 1, '') AS Names
,STUFF((SELECT DISTINCT ',' + Phone
FROM #Employees e1
WHERE e1.PoID = p.PoID
FOR XML PATH (''))
, 1, 1, '') AS Phones
,STUFF((SELECT DISTINCT ',' + Email
FROM #Employees e1
WHERE e1.PoID = p.PoID
FOR XML PATH (''))
, 1, 1, '') AS Emails
FROM #PO p
Result
Below you can see the entire script with test data
declare #po table(PoID int, PO int, Name varchar(100),City varchar(100),State varchar(100))
insert into #po
select 1,55,'Jasons Company','Miami','FL' union
select 2,66,'Mikes Company','NewYork','NY' union
select 3,77,'Sallys Company','Dallas','TX'
declare #Employees table(EmployeeID int, Name varchar(100),Phone varchar(100),Email varchar(100), PoID int)
insert into #Employees
select 1,'John','123-123-1233','j#j.com',1 union
select 2,'Alex','234-234-2344','a#a.com',1 union
select 3,'Cindy','345-345-3455','c#c.com',2 union
select 4,'Jessica','356-356-3566','j#j.com',3
SELECT p.*,
STUFF((SELECT DISTINCT ',' + Name
FROM #Employees e1
WHERE e1.PoID = p.PoID
FOR XML PATH (''))
, 1, 1, '') AS Names
,STUFF((SELECT DISTINCT ',' + Phone
FROM #Employees e1
WHERE e1.PoID = p.PoID
FOR XML PATH (''))
, 1, 1, '') AS Phones
,STUFF((SELECT DISTINCT ',' + Email
FROM #Employees e1
WHERE e1.PoID = p.PoID
FOR XML PATH (''))
, 1, 1, '') AS Emails
FROM #PO p
You can use this.
DECLARE #PO TABLE (PoID INT, PO INT, Name VARCHAR(20), City VARCHAR(20), State vARCHAR(10))
INSERT INTO #PO
VALUES
(1, 55, 'Jasons Company','Miami','FL'),
(2, 66, 'Mikes Company','NewYork','NY'),
(3, 77, 'Sallys Company','Dallas','TX')
DECLARE #Employees TABLE (EmployeeID INT, Name VARCHAR(20), Phone VARCHAR(20), Email VARCHAR(20), PoID INT)
INSERT INTO #Employees
VALUES
(1,'John','123-123-1233','j#j.com',1 ),
(2,'Alex','234-234-2344','a#a.com',1),
(3,'Cindy','345-345-3455','c#c.com',2),
(4,'Jessica','356-356-3566','j#j.com',3)
SELECT
*,
STUFF ( (SELECT
', ' + Name + '/' + Email
FROM
#Employees e WHERE e.PoID = p.PoID FOR XML PATH('') ) ,1,1,'') [names/emails]
FROM
#PO p
Result
PoID PO Name City State names/emails
----------- ----------- -------------------- -------------------- ---------- -------------------
1 55 Jasons Company Miami FL John/j#j.com, Alex/a#a.com
2 66 Mikes Company NewYork NY Cindy/c#c.com
3 77 Sallys Company Dallas TX Jessica/j#j.com
Am able to parse the first and last name, from full name, how do I parse the Middle Name? There are no titles used such as 'MR','MS','DR','FR', 'MRS','LRD','SIR', 'LORD','LADY','MISS','PROF so I think I can use the substring. The name format can be firstname middlename lastname, or firstname lastname, with the space in the middle.
UPDATE p
SET p.LAST_NAME = c.LASTNAME --tested that join is correct, contact name is combined, will need to parse it out ***, need to reference inserted
--Need FIRST_NAME, MIDDLE_NAME, LAST_NAME
p.FIRST_NAME = SUBSTRING(c.CONTACT, 1, CHARINDEX(' ', c.CONTACT) - 1) AS FirstName,
p.MIDDLE_NAME = --need middle name
p.LAST_NAME = SUBSTRING(CONTACT, CHARINDEX(' ', CONTACT) + 1, len(CONTACT)) AS LastName
FROM GMUnitTest.dbo.CONTACT1 c
JOIN PCUnitTest.dbo.PEOPLE p
ON p.PEOPLE_ID = c.KEY4
WHERE c.Key1 = '31';
Based on what you said, that there must be a middle name, you can use something like this:
declare #table table (fullName varchar(256))
insert into #table values
('First Middle Last'),
('John Mary-Lou Smith'),
('Frank NMN Sanatra')
select
CHARINDEX(' ',fullName,1)
,left(fullName,CHARINDEX(' ',fullName,1) - 1) as FirstName
,substring(fullName,CHARINDEX(' ',fullName,1) + 1,(len(fullName) - CHARINDEX(' ',fullName,1)) - charindex(' ',reverse(fullName),1)) as MiddleName
,right(fullName,charindex(' ',reverse(fullName),1)) as LastName
from
#table
I was wondering how can I separate a column containing the following:
BURGER, Petrus (CHV 494081)
Into 3 columns:
FirstName, LastName, ID
SELECT
a[2] AS FirstName,
a[1] AS LastName,
a[3] AS ID
FROM (
SELECT regexp_matches(column_name, '(.+), (.+) \((.+)\)')
FROM table_name
) t(a)