I have a column in my SQL Server 2008 database that contains c/o Full Name. I'm having issues getting the First and Last names separated. I have the c/o in its own column, but I need the First/Last Names. I know that there is an issue with the second and third case statement, but I'm not sure what I need to change. Should I be storing index variables somewhere to reference them?
Declare #t table ( [name] varchar(100) )
INSERT INTO #t ( Name )
SELECT Street1 FROM tblPeople
WHERE CO = 'Y' AND LastName NOT LIKE 'SUMMERHAVEN INC' AND Street1 Like '%c/o%'
SELECT
[name],
CHARINDEX(' ', [name]),
CASE WHEN CHARINDEX(' ', [name]) > 0 THEN
LEFT([name],CHARINDEX(' ',[name])-1)
ELSE
[name]
END as CO,
CASE WHEN CHARINDEX(' ', [name]) > 0 THEN
SUBSTRING([name],CHARINDEX(' ',[name])+1, ( LEN([name]) - CHARINDEX(' ',[name])+1) )
ELSE
NULL
END as FIRST_NAME,
CASE WHEN CHARINDEX(' ', [name]) > 0 THEN
SUBSTRING([name],CHARINDEX(' ',[name])+1, ( LEN([name]) - CHARINDEX(' ',[name])+1) )
ELSE
NULL
END as LAST_NAME
FROM #t
To my surprise, PARSENAME() was available in 2008
Consider the following
Declare #YourTable table (Name varchar(50))
Insert Into #YourTable values
('c/o Cher')
,('c/o John Smith')
,('John Smith')
Select *
,FirstName=parsename(replace(ltrim(rtrim(replace(name,'c/o',''))),' ','.'),2)
,LastName =parsename(replace(ltrim(rtrim(replace(name,'c/o',''))),' ','.'),1)
From #YourTable
Returns
Name FirstName LastName
c/o Cher NULL Cher
c/o John Smith John Smith
John Smith John Smith
Disclosure: this is a bad idea to parse the data like this, but here you go:
Declare #t table ( [name] varchar(100) )
insert into #t ( Name ) values ('c/o Full Name')
SELECT
CASE WHEN CHARINDEX(' ', [name]) > 0 THEN
LEFT([name],CHARINDEX(' ',[name])-1)
ELSE
[name]
END as CO,
CASE WHEN CHARINDEX(' ', [name]) > 0 THEN
SUBSTRING([name],CHARINDEX(' ',[name])+1, CHARINDEX(' ',[name]) )
ELSE
NULL
END as FIRST_NAME,
CASE WHEN CHARINDEX(' ', [name]) > 0 THEN
SUBSTRING([name],CHARINDEX(' ',[name], CHARINDEX(' ',[name])+1), len([name]))
ELSE
NULL
END as LAST_NAME
FROM #t
Here's an approach using Common Table Expressions which so that the logic for finding the spaces to break on is reasonably self-documenting.
Declare #t table ( [name] varchar(100) )
insert into #t ( Name )
select 'one two three'
union select 'a bc def'
union select 'one two'
union select 'one'
;with cte1 as
(
select name
,charindex(' ', name) FirstSpace
from #t
)
, cte2 as (
select name
, FirstSpace
,charindex(' ', name, FirstSpace+1) SecondSpace
from cte1
)
select name
, FirstSpace
, SecondSpace
, case when FirstSpace=0 then name else substring(name, 1, FirstSpace-1) end Company
, case when SecondSpace=0 then null else substring(name, FirstSpace+1, SecondSpace-FirstSpace-1) end FirstName
, case when SecondSpace=0 or SecondSpace=len(name) then null else substring(name, SecondSpace+1, len(name)-SecondSpace) end LastName
from cte2
Related
How do I split a string which can contain 2 names into Person1 and Person2 ? There is no delimiter between the names, there is not always a second person for each row and not necessarily a middle initial/name for either first or second person and only sometimes the second name will be separated with an βANDβ
Examples of Names are as follows
JANE MIDDLETON John MIDDLETON
SUE FRACARO BOB FRACARO
TONY FRENCH
JOHN EDUARDO OCHOA AND JANE ADRIANA OCHOA
TONY JOHN CARPENTER TONYA CARPENTER
Desired Output Design
Person 1 First Name
Person 1 Middle Name
Person 1 Last Name
Person 2 First Name
Person 2 Middle Name
Person 2 Last Name
Create a function for splitting string values in question from some table column:
CREATE FUNCTION [dbo].[Fn_Splittemp]
(
#text VARCHAR(8000)
, #delimiter VARCHAR(20) = ' '
)
RETURNS #String TABLE
(
Position INT IDENTITY PRIMARY KEY
, StringValue VARCHAR(8000)
)
AS
BEGIN
DECLARE #index INT
SET #index = -1
WHILE (LEN(#text) >0)
BEGIN
SET #index = CHARINDEX(#delimiter, #text)
IF (#index = 0) AND (LEN(#text) > 0)
BEGIN
INSERT INTO #string VALUES (#text)
BREAK
END
IF (#index > 1)
BEGIN
INSERT INTO #String VALUES (LEFT(#text, (#index-1)))
SET #text = RIGHT(#text, (LEN(#text)-#index))
END
ELSE
SET #text = RIGHT(#text, (LEN(#text)-#index))
END
RETURN
END
GO
Splitting, cleaning and assigning to respective name_columns:
CREATE TABLE #t0 (rid INT IDENTITY, rawnames VARCHAR(8000));
GO
INSERT INTO #t0 VALUES ('JANE MIDDLETON John MIDDLETON'),
('SUE FRACARO BOB FRACARO'),
('TONY FRENCH'),
('JOHN EDUARDO OCHOA AND JANE ADRIANA OCHOA'),
('TONY JOHN CARPENTER TONYA CARPENTER');
GO
SELECT n.rid, n.rawnames, fn.StringValue AS Names,
COUNT(*) OVER(PARTITION BY rawnames) AS wordcount,
ROW_NUMBER() OVER(PARTITION BY fn.stringvalue,rawnames ORDER BY fn.stringvalue) AS LastNameids,
fn.Position
INTO #t1
FROM #t0 n
cross apply dbo.Fn_Splittemp(n.rawnames, ' ') AS fn
GO
SELECT rid, rawnames, Position AS Pid,
PersonName, LastName INTO #t2
FROM
(SELECT t.rid, t.rawnames, t.names AS Lastname, LTRIM(RTRIM(REPLACE(f.StringValue,'and',''))) AS PersonName, f.Position
FROM
(SELECT replace(sqa.rawnames,sqa.Names,sqa.Names+',') AS delimstr , sqa.*
FROM #t1 sqa
WHERE wordcount<=3 AND position = (SELECT MAX(position) from #t1 crq where crq.rid = sqa.rid)
)t
cross apply dbo.Fn_Splittemp(delimstr,',') f
UNION ALL
SELECT b.rid, b.rawnames, b.Names AS Lastname, LTRIM(RTRIM(REPLACE(f.StringValue,'and',''))) AS PersonName, f.Position
FROM
(SELECT replace(rawnames,names,names+',') AS delimstr, *
FROM #t1
WHERE wordcount>3 AND LastNameids>1)b
cross apply dbo.Fn_Splittemp(delimstr,',') f
)sqt
GO
SELECT * INTO #t3 FROM #t2 cross apply dbo.Fn_Splittemp(personname, ' ');
GO
SELECT t.rawnames, fina.Firstname, fina.MiddleName, fina.LastName
FROM #t0 t
JOIN (
SELECT rid, pid, [1] AS Firstname, NULL AS MiddleName, [2] AS LastName
FROM
(SELECT * FROM (SELECT rid, pid, position, stringvalue,
COUNT(*) OVER(PARTITION BY rid, pid) AS cnt FROM #t3)a
WHERE a.cnt <=2)apiv
PIVOT
(MAX(stringvalue)
FOR position IN ([1],[2])
)piva
UNION ALL
SELECT rid, pid, [1] AS Firstname, [2] AS MiddleName, [3] AS LastName
FROM
(SELECT * FROM (SELECT rid, pid, position, stringvalue,
COUNT(*) OVER(PARTITION BY rid, pid) AS cnt FROM #t3)a
WHERE a.cnt >2)apiv
PIVOT
(MAX(stringvalue)
FOR position IN ([1],[2],[3])
)piva
)fina
ON fina.rid = t.rid;
I have Description column in a table
Description
---------------
AA Check
B1 Check
RD/AA Check
WD_FA Examine
FF Examine
AA Pass
B2 Check
Examine
The desired output
Description
---------------
Check
Examine
Pass
Basically a case statement where it truncates from the left side of the cell. NOTE that the list goes on with different names and conditions, and some cells do not need modification (like the last row), so something similar to a case statement but not returning NULL if I did not specify the condition
Thank you
This removes the data up to the 1st space
case when x like '% %'
then substring(x, charindex(' ', x) +1, 8000)
else x
end
'AA Examine Device' -> 'Examine Device'
And this extracts the last word:
case when x like '% %'
then right(x, charindex(' ', reverse(x)) -1)
else x
end
'AA Examine Device' -> 'Device'
Following the white space that you have, and using DISTINCT, this gets the last word following a white space or returns the word if it's the only word.
declare #Description table (Description varchar(64))
insert into #Description
values
('AA Check'),
('B1 Check'),
('RD/AA Check'),
('WD_FA Examine'),
('FF Examine'),
('AA Pass'),
('B2 Check'),
('Examine')
select distinct
right([Description],len([Description]) - charindex(' ',[Description]))
from #Description
You can do it like below :
select distinct substring(Description, charindex(' ', Description) + 1, len(Description))
The question is too broad, but you can use something like that
DECLARE #Product TABLE (
[Description] nvarchar(255),
Condition int
);
INSERT #Product ([Description], Condition)
select 'AA Check', 1 union all
select 'B1 Check', 2 union all
select 'RD/AA Check', 3 union all
select 'WD_FA Examine', 3 union all
select 'FF Examine', 4 union all
select 'AA Pass', 1 union all
select 'B2 Check', 5 union all
select 'Examine', 6
select
[Description],
case
when Condition = 1 then replace([Description],'AA ','')
when Condition = 2 then replace([Description],'B1 ','')
when Condition = 3 then ltrim(rtrim(right([Description],len([Description]) - 5)))
when Condition = 5 then replace([Description],'B2 ','')
when Condition = 6 then [Description]
else
''
end as 'NewDescription'
from #Product
I hope it helps π
Perhaps something like this:
;WITH CTE (Column1) AS (
SELECT * FROM (
VALUES
(' AA Check '), (' B1 Check'), (' RD/AA Check '), (' WD_FA Examine '), (' FF Examine '),
(' AA Pass '), (' B2 Check '), (' Examine ')
) AS A (Column1)
)
SELECT
CASE WHEN CHARINDEX('Check', Column1) > 0 THEN SUBSTRING(Column1, CHARINDEX('Check', Column1), 5)
WHEN CHARINDEX('Examine', Column1) > 0 THEN SUBSTRING(Column1, CHARINDEX('Examine', Column1), 7)
WHEN CHARINDEX('Pass', Column1) > 0 THEN SUBSTRING(Column1, CHARINDEX('Pass', Column1), 4)
END AS Results
FROM CTE
It would be painful if you have a lot of variables though.
CREATE TABLE [A] ( [Description] VARCHAR(100));
INSERT [A]
VALUES
---------------
( 'AA Check' )
,( 'B1 Check' )
,( 'RD/AA Check' )
,( 'WD_FA Examine' )
,( 'FF Examine' )
,( 'AA Pass' )
,( 'B2 Check' )
,( 'Examine' )
,( 'Examine Device' );
SELECT DISTINCT
CASE
WHEN [Description] COLLATE Latin1_General_BIN LIKE '[A-Z][a-z]%' THEN
[Description]
WHEN [Description] COLLATE Latin1_General_BIN LIKE '[A-Z][A-Z0-9]%' THEN
SUBSTRING([Description], CHARINDEX(' ', [Description]) + 1, 8000)
END AS [Description]
FROM
[A];
DROP TABLE [A];
I have a name field in Students table which is a comma separated string in format "LastName, FirstName, Middle Name".While doing a select statement in SQL query I need to break this up into separate fields.How can I achieve this in SQL?.Some times Middle intial won't be available.
SUBSTRING(Name,CHARINDEX(',',Name,1)+2,LEN(Name)) AS FirstName,
SUBSTRING(Name,1,CHARINDEX(',',Name,1)-1) AS LastName,
Above code works fine when there is no Middle name.
This should give you what you need:
declare #tmp table (fullname varchar(100));
insert #tmp values('James, Billy, L'), ('John, Snow');
select
fullname
, [Last Name]
, case
when charindex(',', Remainder, 0) > 0
then ltrim(substring(Remainder, 0, charindex(',', Remainder, 0)))
else ltrim(Remainder)
end [First Name]
, case
when charindex(',', Remainder, 0) = 0
then NULL
else ltrim(substring(Remainder, charindex(',', Remainder, 0) + 1, len(Remainder)))
end [Middle Name]
from
(select
fullname
, substring(fullname, 0, charindex(',', fullname, 0)) [Last Name]
, substring(fullname, charindex(',', fullname, 0) + 1, len(fullname)) [Remainder]
from #tmp) result;
First just find the occurrences of comma(,) in the string. Then use CASE expression to get the number of comma. If there is 2 comma then we can assume that middle name is also there. If 1 then only first name and last name. Then use the combinations of LEFT, RIGHT, SUBSTRING, CHARINDEX string functions.
Query
select t.name,
left(
t.name,
charindex(',', t.name, 1) - 1
) last_name,
case t.comma_num
when 2
then substring(
t.name,
charindex(',', t.name, 1) + 1,
len(name) -
(charindex(',', t.name, 1) + 1) - charindex(',', reverse(t.name), 1) + 1
)
when 1
then right(
t.name,
charindex(',', reverse(t.name), 1) - 1
)
else null end as first_name,
case t.comma_num
when 2
then right(
t.name, charindex(',', reverse(t.name), 1) - 1
)
else null end as middle_name
from (
select name,
len(name) - len(replace(name, ',', '')) comma_num
from [your_table_name]
)t;
Find demo here
Use CTE and SUBSTRING AND CHARINDEX funntions
DECLARE #Name VARCHAR(100) = 'James, Billy, L'
--DECLARE #Name VARCHAR(100) = 'James, '', L'
;WITH _CTE ( SplitedNames ,RemainStr) AS
(
SELECT SUBSTRING(#Name,0,CHARINDEX(',',#Name)),
SUBSTRING(#Name,CHARINDEX(',',#Name)+1,LEN(#Name))
UNION ALL
SELECT CASE WHEN CHARINDEX(',',RemainStr) = 0 THEN RemainStr ELSE
SUBSTRING(RemainStr,0,CHARINDEX(',',RemainStr)) END,
CASE WHEN CHARINDEX(',',RemainStr) = 0 THEN '' ELSE
SUBSTRING(RemainStr,CHARINDEX(',',RemainStr)+1,LEN(RemainStr))
END
FROM _CTE
WHERE RemainStr <> ''
)
SELECT SplitedNames FROM _CTE
I have data such as this:
Inventors column in my table
Hundley; Edward; Ana
Isler; Hunsberger
Hunsberger;Hundley
Names are separated by ;. I want to write a SQL query which sums up the count.
Eg. The result should be:
Hundley 2
Isler 1
Hunsberger 2
Edward 1
Ana 1
I could do a group by but this is not a simple group by as you can see. Any ideas/thoughts on how to get this output?
Edit: Changed results so it doesn't create any confusion that a row only contains 2 names.
You can take a look at this. I certainly do not recommend this way if you have lots of data, BUT you can do some modifications and use it and it works like a charm!
This is the new code for supporting unlimited splits:
Declare #Table Table (
Name Nvarchar(50)
);
Insert #Table (
Name
) Select 'Hundley; Edward; Anna'
Union Select 'Isler; Hunsberger'
Union Select 'Hunsberger; Hundley'
Union Select 'Anna'
;
With Result (
Part
, Remained
, [Index]
, Level
) As (
Select Case When CharIndex(';', Name, 1) = 0
Then Name
Else Left(Name, CharIndex(';', Name, 1) - 1)
End
, Right(Name, Len(Name) - CharIndex(';', Name, 1))
, CharIndex(';', Name, 1)
, 1
From #Table
Union All
Select LTrim(
Case When CharIndex(';', Remained, 1) = 0
Then Remained
Else Left(Remained, CharIndex(';', Remained, 1) - 1)
End
)
, Right(Remained, Len(Remained) - CharIndex(';', Remained, 1))
, CharIndex(';', Remained, 1)
, Level
+ 1
From Result
Where [Index] <> 0
) Select Part
, Count(*)
From Result
Group By Part
Cheers
;with cte as
(
select 1 as Item, 1 as Start, CHARINDEX(';',inventors, 1) as Split, Inventors from YourInventorsTable
union all
select cte.Item+1, cte.Split+1, nullif(CHARINDEX(';',inventors, cte.Split+1),0), inventors as Split
from cte
where cte.Split<>0
)
select rTRIM(lTRIM(SUBSTRING(inventors, start,isnull(split,len(inventors)+1)-start))), count(*)
from cte
group by rTRIM(lTRIM(SUBSTRING(inventors, start,isnull(split,len(inventors)+1)-start)))
You can create a split function to split the col values
select splittedValues.items,count(splittedValues) from table1
cross apply dbo.split(col1,';') splittedValues
group by splittedValues.items
DEMO in Sql fiddle
first make one function who take your comma or any other operator(;) separated string into one table and by using that temp table, apply GROUP function on that table.
So you will get count for separate value.
"select d.number,count(*) from (select number from dbo.CommaseparedListToTable('Hundley;Edward;Ana;Isler;Hunsberger;Hunsberger;Hundley',';'))d
group by d.number"
declare #text nvarchar(255) = 'Edward; Hundley; AnaIsler; Hunsberger; Hunsberger; Hundley ';
declare #table table(id int identity,name varchar(50));
while #text like '%;%'
Begin
insert into #table (name)
select SUBSTRING(#text,1,charindex(';',#text)-1)
set #text = SUBSTRING(#text, charindex(';',#text)+1,LEN(#text))
end
insert into #table (name)
select #text
select name , count(name ) counts from #table group by name
Output
name count
AnaIsler 1
Hundley 2
Hunsberger 2
Edward 1
I have a problem splitting single column values to multiple column values.
For Example:
Name
------------
abcd efgh
ijk lmn opq
asd j. asdjja
asb (asdfas) asd
asd
and I need the output something like this:
first_name last_name
----------------------------------
abcd efgh
ijk opq
asd asdjja
asb asd
asd null
The middle name can be omitted (no need for a middle name) The columns are already created and need to insert the data from that single Name column.
Your approach won't deal with lot of names correctly but...
SELECT CASE
WHEN name LIKE '% %' THEN LEFT(name, Charindex(' ', name) - 1)
ELSE name
END,
CASE
WHEN name LIKE '% %' THEN RIGHT(name, Charindex(' ', Reverse(name)) - 1)
END
FROM YourTable
An alternative to Martin's
select LEFT(name, CHARINDEX(' ', name + ' ') -1),
STUFF(name, 1, Len(Name) +1- CHARINDEX(' ',Reverse(name)), '')
from somenames
Sample table
create table somenames (Name varchar(100))
insert somenames select 'abcd efgh'
insert somenames select 'ijk lmn opq'
insert somenames select 'asd j. asdjja'
insert somenames select 'asb (asdfas) asd'
insert somenames select 'asd'
insert somenames select ''
insert somenames select null
;WITH Split_Names (Name, xmlname)
AS
(
SELECT
Name,
CONVERT(XML,'<Names><name>'
+ REPLACE(Name,' ', '</name><name>') + '</name></Names>') AS xmlname
FROM somenames
)
SELECT
xmlname.value('/Names[1]/name[1]','varchar(100)') AS first_name,
xmlname.value('/Names[1]/name[2]','varchar(100)') AS last_name
FROM Split_Names
and also check the link below for reference
http://jahaines.blogspot.in/2009/06/converting-delimited-string-of-values.html
What you need is a split user-defined function. With that, the solution looks like
With SplitValues As
(
Select T.Name, Z.Position, Z.Value
, Row_Number() Over ( Partition By T.Name Order By Z.Position ) As Num
From Table As T
Cross Apply dbo.udf_Split( T.Name, ' ' ) As Z
)
Select Name
, FirstName.Value
, Case When ThirdName Is Null Then SecondName Else ThirdName End As LastName
From SplitValues As FirstName
Left Join SplitValues As SecondName
On S2.Name = S1.Name
And S2.Num = 2
Left Join SplitValues As ThirdName
On S2.Name = S1.Name
And S2.Num = 3
Where FirstName.Num = 1
Here's a sample split function:
Create Function [dbo].[udf_Split]
(
#DelimitedList nvarchar(max)
, #Delimiter nvarchar(2) = ','
)
RETURNS TABLE
AS
RETURN
(
With CorrectedList As
(
Select Case When Left(#DelimitedList, Len(#Delimiter)) <> #Delimiter Then #Delimiter Else '' End
+ #DelimitedList
+ Case When Right(#DelimitedList, Len(#Delimiter)) <> #Delimiter Then #Delimiter Else '' End
As List
, Len(#Delimiter) As DelimiterLen
)
, Numbers As
(
Select TOP( Coalesce(DataLength(#DelimitedList)/2,0) ) Row_Number() Over ( Order By c1.object_id ) As Value
From sys.columns As c1
Cross Join sys.columns As c2
)
Select CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position
, Substring (
CL.List
, CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen
, CharIndex(#Delimiter, CL.list, N.Value + 1)
- ( CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen )
) As Value
From CorrectedList As CL
Cross Join Numbers As N
Where N.Value <= DataLength(CL.List) / 2
And Substring(CL.List, N.Value, CL.DelimiterLen) = #Delimiter
)
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(rent, ' ', 1), ' ', -1) AS currency,
SUBSTRING_INDEX(SUBSTRING_INDEX(rent, ' ', 3), ' ', -1) AS rent
FROM tolets
I used it recently:
select
substring(name,1,charindex(' ',name)-1) as Col1,
substring(name,charindex(' ',name)+1,len(name)) as Col2
from TableName
Here is how I did this on a SQLite database:
SELECT SUBSTR(name, 1,INSTR(name, " ")-1) as Firstname,
SUBSTR(name, INSTR(name," ")+1, LENGTH(name)) as Lastname
FROM YourTable;
Hope it helps.