Getting the middle name from a full name field - sql

So, I've got functions to get the first and last names, like so:
create function udf_get_first_name (#string nvarchar(100))
returns nvarchar(50)
as
begin
declare #first_name nvarchar(50)
set #string = ltrim(#string)
set #string = rtrim(#string)
if dbo.udf_get_number_of_spaces(#string) > 0
set #first_name = left(#string, charindex(' ',#string) -1)
else
set #first_name = #string
return #first_name
end
create function udf_get_last_name (#string nvarchar(100))
returns nvarchar(50)
as
begin
set #string = ltrim(#string)
set #string = rtrim(#string)
if dbo.udf_get_number_of_spaces (#string) > 0
begin
set #string = reverse(#string)
set #string = left(#string, charindex(' ', #string) -1)
set #string = reverse(#string)
end
return #string
end
I need to be able to get the middle name, and just can't wrap my head around what I've been reading through my searching so far. Not sure if I'm just being dumb or not.
I also need to be able to sort a name formatted as L/M/F, into the proper columns as well, which I'm having an even harder time with.
Edit: Not all the records have middle names.

You can use the following solution, using a function to get a part of the name or the fullname in a specified format:
--
-- function to get a part of a fullname or to reformat the fullname.
-- #fullname - the fullname to get the part from or to reformat.
-- #format - the format of the output using F (firstname), M (middlename) and L (lastname).
-- the function returns the fullname in specified format or NULL if input is not valid
-- or the part of name is empty.
--
CREATE FUNCTION GetNamePart(#fullname VARCHAR(200), #format VARCHAR(30))
RETURNS VARCHAR(200)
AS
BEGIN
-- replace multiple spaces of the fullname and trim the result.
SET #fullname = LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(#fullname, ' ', '<>'), '><', ''), '<>', ' ')))
-- get the different name parts (firstname, middlename and lastname) of the fullname.
DECLARE #first_name VARCHAR(100)
SET #first_name = LTRIM(RTRIM(LEFT(#fullname, CHARINDEX(' ', #fullname))))
DECLARE #last_name VARCHAR(100)
SET #last_name = LTRIM(RTRIM(RIGHT(#fullname, CHARINDEX(' ', REVERSE(#fullname)))))
DECLARE #middle_name VARCHAR(100)
SET #middle_name = LTRIM(RTRIM(SUBSTRING(#fullname, LEN(#first_name) + 1, LEN(#fullname) - LEN(#first_name) - LEN(#last_name))))
-- init the formatted name of the fullname.
DECLARE #formatted_name VARCHAR(100)
-- return only the formatted name if format string is valid.
IF PATINDEX('%[^LMF]%', UPPER(#format)) > 0
SET #formatted_name = ''
ELSE
BEGIN
SET #format = REPLACE(REPLACE(REPLACE(#format, 'M', '##M##'), 'L', '##L##'), 'F', '##F##')
SET #formatted_name = LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(UPPER(#format), '##F##', #first_name + ' '), '##M##', #middle_name + ' '), '##L##', #last_name + ' ')))
END
-- check the input (#fullname) for valid value (firstname, lastname or firstname, middlename, lastname).
IF PATINDEX('%_ %_% _%', #fullname) = 0 AND PATINDEX('%_ _%', #fullname) = 0
SET #formatted_name = ''
-- return the new formatted name and replace multiple spaces.
RETURN NULLIF(REPLACE(REPLACE(REPLACE(#formatted_name, ' ', '<>'), '><', ''), '<>', ' '), '')
END
This function GetNamePart is using two parameters (#fullname and #format). The first parameter #fullname is the fullname containing the firstname, lastname and if available the middlename. The second parameter is defining the output format of the name. You can use the letters F (firstname), M (middlename) and L (lastname) to define the format of the output.
So you can use the function GetNamePart to get the middlename of the fullname:
SELECT dbo.GetNamePart(fullname, 'M') FROM table_name
... or to reformat the fullname like this:
SELECT dbo.GetNamePart(fullname, 'LMF') FROM table_name
demo on dbfiddle.uk (demo and test cases)
But you can also use a SELECT query to get the various parts of the name without a function:
SELECT
LTRIM(RTRIM(LEFT(fullname, CHARINDEX(' ', fullname)))) AS first_name,
LTRIM(RTRIM(RIGHT(fullname, CHARINDEX(' ', REVERSE(fullname))))) AS last_name,
LTRIM(RTRIM(CASE WHEN PATINDEX('%_ %_% _%', fullname) > 0 THEN SUBSTRING(fullname, CHARINDEX(' ', fullname) + 1, (CHARINDEX(' ', fullname, CHARINDEX(' ', fullname)+1)-(CHARINDEX(' ', fullname) + 1))) ELSE '' END)) AS middle_name
FROM table_name
demo on dbfiddle.uk

Similar to Sebastian Brosch's answer. I also added the TRIM function after I saw his answer. In this query, it's not necessary. But it's something nice to have. For example, if the user added multiple spaces by mistake, this will remove that.
There might be a better or simpler way to get first, middle and last name. But this is the way I come up with at the moment.
CREATE FUNCTION dbo.SplitFullName(
#FullName NVARCHAR(MAX),
#Format NVARCHAR(MAX)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #FN NVARCHAR(MAX);
DECLARE #MN NVARCHAR(MAX);
DECLARE #LN NVARCHAR(MAX);
DECLARE #RV NVARCHAR(MAX);
SET #FN = RTRIM(LTRIM(SUBSTRING(#FullName,0, CHARINDEX(' ',#FullName))));
SET #MN = RTRIM(LTRIM(SUBSTRING(#FullName, CHARINDEX(' ',#FullName) + 1 , LEN(#FullName) - (CHARINDEX(' ',#FullName) + CHARINDEX(' ',REVERSE(#FullName)))+1)));
SET #LN = RTRIM(LTRIM(REVERSE(SUBSTRING(REVERSE(#FullName),0, CHARINDEX(' ',REVERSE(#FullName))))));
IF (#Format='FN')
SET #RV = CASE WHEN LEN(#FN) = 0 THEN NULL ELSE #FN END;
ELSE IF (#Format='MN')
SET #RV = CASE WHEN LEN(#MN) = 0 THEN NULL ELSE #MN END;
ELSE IF (#Format='LN')
SET #RV = CASE WHEN LEN(#LN) = 0 THEN NULL ELSE #LN END;;
ELSE
SET #RV = CONCAT(#LN, ' ', CASE WHEN LEN(#MN) = 0 THEN NULL ELSE CONCAT(#MN , ' ') END, #FN);
RETURN #RV;
END;
Example 01
SELECT dbo.SplitFullName('Antonio P. Green', 'FN') AS FN,
dbo.SplitFullName('Antonio P. Green', 'MN') AS MN,
dbo.SplitFullName('Antonio P. Green', 'LN') AS LN,
dbo.SplitFullName('Antonio P. Green', 'LMF') AS LMF;
+---------+----+-------+------------------+
| FN | MN | LN | LMF |
+---------+----+-------+------------------+
| Antonio | P. | Green | Green P. Antonio |
+---------+----+-------+------------------+
Example 02
select dbo.SplitFullName('Cindy Bertha Collier Sproles', 'FN') AS FN,
dbo.SplitFullName('Cindy Bertha Collier Sproles', 'MN') AS MN,
dbo.SplitFullName('Cindy Bertha Collier Sproles', 'LN') AS LN,
dbo.SplitFullName('Cindy Bertha Collier Sproles', 'LMF') AS LMF;
+-------+----------------+---------+------------------------------+
| FN | MN | LN | LMF |
+-------+----------------+---------+------------------------------+
| Cindy | Bertha Collier | Sproles | Sproles Bertha Collier Cindy |
+-------+----------------+---------+------------------------------+
Example 03
SELECT dbo.SplitFullName('Tristan Jackson', 'FN') AS FN,
dbo.SplitFullName('Tristan Jackson', 'MN') AS MN,
dbo.SplitFullName('Tristan Jackson', 'LN') AS LN,
dbo.SplitFullName('Tristan Jackson', 'LMF') AS LMF;
+---------+------+---------+-----------------+
| FN | MN | LN | LMF |
+---------+------+---------+-----------------+
| Tristan | NULL | Jackson | Jackson Tristan |
+---------+------+---------+-----------------+

You can handle this using Multiple comma separated CTE.
declare #str nvarchar(max) ='kareena kapoor khan';
with
t0 AS (select charindex(' ',#str) pos, #str name ),
t1 AS (select charindex(' ',#str,pos+1)pos,#str name from t0)
select substring(t0.name,0,t0.pos) "firstName",
substring(t0.name,t0.pos+1,(t1.pos-t0.pos)) "MiddleName",
substring(t0.name,t1.pos+1,(len(t0.name)- t1.pos)) "Lastname"
from t0
inner join t1 on t0. name= t1.name
output
|firstName | MiddleName |Lastname
|kareena | kapoor |khan
Also, Instead of creating 3 function for first name , middle name and last name you can just create a single function and pass parameter as #namepart.

The future is start as sql-server 2016:
use STRING_SPLIT function
Use Northwind
Go
SELECT ProductID, value
FROM Products
CROSS APPLY STRING_SPLIT(ProductName, ' ');
by this query you can split names... then use by Row() function you can choose middle name.
STRING_SPLIT requires the compatibility level to be at least 130. When the level is less than 130, SQL Server is unable to find the STRING_SPLIT function.

Select Ltrim(SUBSTRING(name,CharIndex(' ',name),
CAse When (CHARINDEX(' ',name,CHARINDEX(' ',name)+1)-CHARINDEX(' ',name))<=0 then 0
else CHARINDEX(' ',name,CHARINDEX(' ',name)+1)-CHARINDEX(' ',name) end )) as MiddleName
From TableName

Related

How can I split name in SQL

I have a column in my table with 1000 names. I want to make a new column by splitting the name in new format: Example:
Santosh Kumar Yadav
It should be:
Santosh K Yadav
Middle name with only initials and rest name should be the same.
How can I do it ?
If all you want to do is replace second name with Initial. Here's an idea for MySQL database.
Assuming the name of names column is name & new column where you want to put data is formatted_name. You could try this.
UPDATE Users
SET formatted_name = REPLACE(
name,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ' ', 2), ' ', -1),
LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(name, ' ', 2), ' ', -1), 1)
);
Here's the demo
http://sqlfiddle.com/#!9/4e5f95
Following solution in Java
// get name from database and store in var1
String[] nameType = var1.split (' ');
// divide var1 into firstname middlename lastname by splitting name with 'space'
var1 = nameType [0] + ' ' + nameType [1].substring (0, 1) + ' ' + nameType [2];
// combine name types, but only first letter of middle name
// write var1 in database
Please try to make use of the below code. Its working fine in SQL Server 2012.
Note : This will work only for name with 3 parts.
DECLARE #Table TABLE (Name Varchar(100))
INSERT INTO #Table
(Name)
VALUES
('Santhosh Kumar Yadav'),
('John Thomas Mathew'),
('Thomas Mathew John'),
('Mathew John Thomas'),
('John Mathew Thomas')
SELECT
SUBSTRING(Name,1,CHARINDEX(' ',Name)+1) +
REVERSE(SUBSTRING(REVERSE(Name),1,CHARINDEX(' ',REVERSE(Name)))) AS Name
FROM
#Table
The OP didn't mention the db vendor. The sample version for Oracle:
with mynames (name) as
(select 'Santosh Kumar Yadav' from dual
union all
select 'Abc Defgh' from dual)
select
case when length(name) - length(replace(name, ' ', '')) + 1 < 3 then
name
else
regexp_replace(name,'(^| )([^ ])([^ ])*',' \2',2, 1)
end
from mynames
It replaces only second word in the string when string has more than 2 words.
For this result like
'Santosh Kumar Yadav' into 'Santosh K Yadav'
. You should create a function that convert
from 'Santosh Kumar Yadav' into 'Santosh K Yadav'
create function FullNameToShort(#name varchar(100))
returns varchar(100)
begin
declare #input varchar(100)
set #input=#name
declare #i int
declare #output varchar(100)
declare #ch varchar
declare #lname varchar(25)
declare #flag int
set #flag=0
set #i=1
while #i<=LEN(#input)
begin
if(SUBSTRING(#input,#i,1)=' ')
begin
set #lname=(SUBSTRING(#input,#i,len(#input)-#i+1))
select #ch=(SUBSTRING(#input,#i+1,1))
if(#flag=0)
begin
select #output=(SUBSTRING(#input,0,#i))
set #flag=1
end
set #output=#output+' '+#ch
end
set #i=#i+1
end
select #output=SUBSTRING(#output,0,LEN(#output))
set #output= #output+#lname
return #output
end
select dbo.FullNameToShort('Santosh Kumar Yadav')
Its convert the all middle name into one char
Try this:-
select substring('Santosh Kumar Yadav',1,charindex(' ','Santosh Kumar Yadav')+1) + reverse(substring(reverse('Santosh Kumar Yadav'),1,charindex(' ',reverse('Santosh Kumar Yadav'))))

How to modify data retrieved from select in sql?

suppose i am having some unwanted characters in the data present in a column for eg name column in customers table has data like < ,is there anyway to modify such characters like '<' to blankspace while retrieving this data using select statement? This is to prevent xss scripts showing up due to old data which is having such unwanted characters
e.g:
select *
from customers
returns
Id Name Age city salary
-- ------ --- ---- ------
1 <hari 32 Ahmedabad 4000
2 Khilan 25 Delhi 5678
3 kaushik 23 Kota 234
i want <hari to be displayed as hari when this data is retrieved using select statement.How to achieve this ?
Something like...
SELECT REPLACE(REPLACE(a.name,'<', ''), '>','')
FROM ...
It may be better to write a function to remove special characters. Here the function replaces any character that does not look like a-z,A-Z(if case sensitive),0-9 and Space. You can add more if needed.
For example if you want to retain period(.) the use '[^a-zA-Z0-9 .]'
Function:
CREATE FUNCTION ufn_RemoveSpecialCharacters
(
#String VARCHAR(500),
#Exclude VARCHAR(100),
#CollapseSpaces BIT
)
RETURNS VARCHAR(500)
AS
BEGIN
DECLARE #StartString INT,
#EndString INT,
#FinalString VARCHAR(500),
#CurrentString CHAR(1),
#PreviousString CHAR(1)
SET #StartString = 1
SET #EndString = LEN(ISNULL(#String, ''))
WHILE #StartString <= #EndString
BEGIN
SET #CurrentString = SUBSTRING(#String, #StartString, 1)
SET #PreviousString = SUBSTRING(#String, #StartString-1, 1)
IF #CurrentString LIKE ISNULL(#Exclude,'[^a-zA-Z0-9 ]')
BEGIN
SET #CurrentString = ''
IF #CollapseSpaces = 1
SET #FinalString = CASE WHEN #PreviousString = CHAR(32) THEN ISNULL(#FinalString, '') ELSE ISNULL(#FinalString, '')+' ' END
END
ELSE
BEGIN
SET #FinalString = ISNULL(#FinalString, '') + #CurrentString
IF #CollapseSpaces = 1
BEGIN
SET #FinalString = REPLACE(#FinalString,' ',' ')
END
END
SET #StartString = #StartString + 1
END
--PRINT #String
RETURN LTRIM(RTRIM(#FinalString))
END
GO
Usage:
Does not collapse Spaces
SELECT dbo.ufn_RemoveSpecialCharacters('This #$%string has#$% special #$% characters and spaces))', '[^a-zA-Z0-9 ]', 0)
Collapses multiple Spaces
SELECT dbo.ufn_RemoveSpecialCharacters('This #$%string has#$% special #$% characters and spaces))', '[^a-zA-Z0-9 ]', 1)
Here is the example
SELECT Replace(Column Name, ' ', '') AS C
FROM Contacts
WHERE Replace(Column Name, ' ', '') LIKE 'whatever'
Hope this was helpful

Trouble extracting First and LastName from Full Name column

I am having FullName column and I am extracting the First Name and last name using the following query
select SUBSTRING(FULL_NAME, 1, CHARINDEX(' ', FULL_NAME) - 1) AS FirstName,
SUBSTRING(FULL_NAME, CHARINDEX(' ', FULL_NAME) + 1, 500) AS LastName
from [dbo].[TABLE]
But in the Full Name column there are just First names, some 10 digit phone numbers, 4 digit extensions and some text like 'this is a special case'.
How should I modify my query to accommodate these exceptions? And also when there are only single words in the Full Name column I am getting this following error message:
"Invalid length parameter passed to the LEFT or SUBSTRING function."
Parsing good names from free form fields is not an easy task...
I would suggest a dual approach.
Identify common patterns, i.e. you might find phone number with something like this
Where IsNumeric( Replace(Field,'-','')=1
and you might identify single names with
Where charindex(' ',trim(field))=0
etc.
Once you've identified them, the write code to attempt to split them...
So you might use the code you have above with the following WHERE clause
select SUBSTRING(FULL_NAME, 1, CHARINDEX(' ', FULL_NAME) - 1) AS FirstName,
SUBSTRING(PRQ_BP_CONTACT_NAME, CHARINDEX(' ', FULL_NAME) + 1, 500)
AS LastN
from [dbo].[TABLE]
where charindex(' ',trim(field))>0 and Where IsNumeric( Replace(Field,'-','')=0
Use the WHERE clauses to (a) make sure you only get records you can parse and (b) help identify the oddball cases you'll like need to do by hand...
Good luck
You could go with a function this allows you to put in any logic you need in the transform and keep things a bit more readable :
create function dbo.namepart( #fullname varchar(50), #part varchar(5))
returns varchar(10)
as
begin
declare #first varchar(50)
declare #last varchar(50)
declare #sp int
if #fullname like '%special value%' return ''
if #fullname like '% %'
begin
set #sp = CHARINDEX(' ', #fullname)
set #first = left(#fullname, #sp - 1)
set #last = substring(#fullname,#sp + 1 ,50)
if isnumeric(#last) <> 0 set #last = ''
end
else
begin
set #first = #fullname
set #last = ''
end
if #part like 'f%'
return #first
else
return #last
return ''
end
Sample data
create table blah(
full_name varchar(50)
)
insert into blah values ( 'john smith' ), ('paul 12345'),('evan'),('special value')
And see if it works
select
dbo.namepart(full_name,'first') first,
dbo.namepart(full_name,'last') last,
full_name
from blah
http://sqlfiddle.com/#!6/eb28f/2

SQL Select Value From Comma Delimited List

I have a field in my database called "Notes". It contains a comma delimited list of values.
I want to perform a SELECT Query that only returns the first value in the "Notes" field.
This query would also return additional fields from the database.
for example
SELECT Name, Phone, Notes (only the first value)
FROM Table1
Is this possible, and how do I do it?
You can use CHARINDEX with SUBSTRING:
SELECT Name, Phone, SUBSTRING(Notes, 1, CHARINDEX(',', Notes)) AS first_value
FROM Table1
Demo
DECLARE #csv varchar(50)
SET #csv = 'comma after this, and another,'
SELECT SUBSTRING(#csv, 1, CHARINDEX(',', #csv)) AS first_value
Result
| first_value |
--------------------
| comma after this |
As mentioned in the comments, you should normalize your structure and not have more than one value stored in a single attribute.
SELECT Name, Phone, Left(Notes, CharIndex(',', Notes + ',')) FirstNote
FROM Table1
You need the Notes + ',' bit in the CharIndex to work correctly - see this example (I have included njk's answer)
with Table1(Name, Phone, Notes) as (
select 'abc', '123', 'Some,notes,here' union all
select 'abd', '124', 'Single-note' union all
select 'abe', '125', '' union all
select 'syz', '126', null
)
---
SELECT Name, Phone, Left(Notes, CharIndex(',', Notes + ',')-1) FirstNote
,SUBSTRING(Notes, 0, CHARINDEX(',', Notes)) AS njk
FROM Table1
Results
Name Phone FirstNote njk
---- ----- --------------- ---------------
abc 123 Some Some
abd 124 Single-note
abe 125
syz 126 NULL NULL
SELECT name,
phones,
split_part(notes, ',', 1) as first_notes
FROM Table1
solutions for Select Value From Comma Delimited List
I was looking for a more general answer (not just the first field but an arbitrarily specified one) so I modified Kermit's answer and put it in a function. Here it is in case it helps save somebody else time
CREATE FUNCTION [dbo].[fnGetFieldXFromDelimitedList] (#SearchIn nvarchar(max)
, #Delimiter char(1), #FieldNum int ) RETURNS nvarchar(max) as BEGIN
/*
fnGetFieldXFromDelimitedList(#SearchIn, #Delimiter, #FieldNum)
Returns the Nth value (specified by #FieldNum, first is 1 not 0)
from #SearchIn assuming #SearchIn is a list of multiple values
delimited by #Delimiter
DECLARE #SearchIn nvarchar(max) = 'F1, Field 2, F3,, F5, F6, F7'
DECLARE #Delimiter char(1) = ','
DECLARE #FieldNum int = 7
--*/
--SELECT dbo.fnGetFieldXFromDelimitedList ('F1, Field 2, F3,, F5, F6, F7', ',', 5)
DECLARE #PosStart int = 1 --SUBSTRING(SearchIn, StartPos, StrLen) considers 1 the first character
DECLARE #PosEnd INT = LEN(#SearchIn)
DECLARE #TempString nvarchar(max) = CONCAT(#SearchIn, #Delimiter)
DECLARE #TempNum INT = 1
DECLARE #RetVal nvarchar(max) = ''
--SElECT SUBSTRING(#SearchIn, 1, 1)
SET #PosEnd = CHARINDEX(#Delimiter, #TempString, #PosStart + LEN(#Delimiter))
WHILE #TempNum < #FieldNum AND #PosStart > 0 AND #PosStart < LEN(#TempString) BEGIN
SET #PosStart = CHARINDEX(#Delimiter, #TempString, #PosStart) + LEN(#Delimiter)
SET #PosEnd = CHARINDEX(#Delimiter, #TempString, #PosStart)
SET #TempNum = #TempNum + 1
--SELECT #PosStart, #PosEnd , #TempNum
END --WHILE
IF #TempNum = #FieldNum AND #PosEnd > 0 BEGIN
SET #RetVal = SUBSTRING(#TempString, #PosStart, #PosEnd - #PosStart)
END ELSE BEGIN
SET #RetVal = NULL
END
--SELECT #RetVal
RETURN #RetVal
END

sybase ISNULL - are the conditions too long?

I am trying to unmangle a very old variable. It was a full name entered all in one field and is found in two separate tables. In most newer places the name is in three logical columns, first, middle, last. In these it is all together and I am trying to strip it out to first initial, last name. I found the following here and modified it:
http://dbaspot.com/sqlserver-programming/365656-find-last-word-string.html
DECLARE #full_name VARCHAR(20)
DECLARE #fullname VARCHAR(20)
SELECT #full_name = REVERSE('John A Test')
SELECT #fullname = REVERSE('Joe Q Public')
SELECT #final = ISNULL(
(right(#full_name,1) + '. ' + (REVERSE(SUBSTRING(#full_name, 1,
CHARINDEX(' ',#full_name) - 1)))),
(right(#fullname,1) + '. ' + (REVERSE(SUBSTRING(#fullname, 1,
CHARINDEX(' ',#fullname) - 1 ))))
)
When I leave full_name there it works fine...returns J. Test. When I null it the default should be
J. Public but instead ends up as .. When I test each line separately they work. I tried COALESCE as well with the same results. Is this too many brackets for ISNULL or ????
You have problem with right(#full_name,1) + '. ', for example:
select null+'.'
gives you ..
Try to change your code using case as below:
DECLARE #full_name VARCHAR(20)
DECLARE #fullname VARCHAR(20)
DECLARE #final VARCHAR(20)
SELECT #full_name = null--REVERSE('John A Test')
SELECT #fullname = REVERSE('Joe Q Public')
SELECT #final = case
when #full_name is not null
then (right(#full_name,1) + '. ' + (REVERSE(SUBSTRING(#full_name, 1,
CHARINDEX(' ',#full_name) - 1))))
else (right(#fullname,1) + '. ' + (REVERSE(SUBSTRING(#fullname, 1,
CHARINDEX(' ',#fullname) - 1 ))))
end
select #final