first letters in firstname and lastname uppercase - sql

Assuming I have a table full of names.
firstname.lastname in a single cell.
How can I seperate these into "Firstname Lastname", with uppercase for the first letters? Using TSQL
Sample:
mike.mikeson -> Mike Mikeson
katy.lumberjack -> Katy Lumberjack

One of those times we can use the ParseName function for our benefit ;-)
SELECT original_value
, forename
, surname
, Upper(SubString(forename, 1, 1)) + Lower(Substring(forename, 2, 8000)) AS formatted_forename
, Upper(SubString(surname , 1, 1)) + Lower(Substring(surname , 2, 8000)) AS formatted_surname
FROM (
SELECT name AS original_value
, ParseName(name, 2) AS forename
, ParseName(name, 1) AS surname
FROM (
VALUES ('mike.mikeson')
, ('katy.lumberjack')
) AS users (name)
) AS step1

The below will answer you question as is but as comments have pointed out, you may need to also take into account names that have more than one uppercase letter in either part, such as Mary-Anne McDonald, or those that simply don't conform to your convention.
declare #a table (Name nvarchar(50))
insert into #a values
('fred.bloggs')
,('john.doe')
,('alan.smith')
select Name
,upper(left(Name,1))
+ substring(Name,2,charindex('.',Name,1)-2)
+ ' '
+ upper(substring(Name,charindex('.',Name,1)+1,1))
+ right(Name,len(Name) - charindex('.',Name,1)-1)
as FormattedName
from #a

You can try using concat and substring for this as below
declare #name varchar(50) = 'firstname.lastname'
select case when charindex('.',#name) > 0 then concat(upper(left(#name,1)), substring(#name,2,charindex('.',#name)-2), ' ', upper(substring(#name,charindex('.',#name)+1,1)), substring(#name,charindex('.',#name)+2, len(#name)))
else concat(upper(left(#name,1)), substring(#name,2,len(#name))) end

Related

How to Specify Trim Chars in SQL TRIM

I'm having a table Employee, in that some values are started with ", ". So, I need to remove the comma and white-space at the beginning of the name at the time of SELECT query using LTRIM() - SQL-Server.
My Table : Employee
CREATE TABLE Employee
(
PersonID int,
ContactName varchar(255),
Address varchar(255),
City varchar(255)
);
INSERT INTO Employee(PersonID, ContactName, Address, City)
VALUES ('1001',', B. Bala','21, Car Street','Bangalore');
SELECT PersonID, ContactName, Address, City FROM Employee
Here the ContactName Column has a value ", B. Bala". I need to remove the comma and white-space at the beginning of the name.
Alas, SQL Server does not support the ANSI standard functionality of specifying the characters for LTRIM().
In this case, you can use:
(case when ContactName like ', %' then stuff(ContactName, 1, 2, '')
else ContactName
end)
You could potentially use PATINDEX() in order to get this done.
DECLARE #Text VARCHAR(50) = ', Well Crap';
SELECT STUFF(#Text, 1, PATINDEX('%[A-z]%', #Text) - 1, '');
This would output Well Crap. PATINDEX() will find first letter in your word and cut everything before it.
It works fine even if there's no leading rubbish:
DECLARE #Text VARCHAR(50) = 'Mister Roboto';
SELECT STUFF(#Text, 1, PATINDEX('%[A-z]%', #Text) - 1, '');
This outputs Mister Roboto
If there are no valid characters, let's say ContactName is , 9132124, :::, this would output NULL, if you'd like to get blank result, you can use COALESCE():
DECLARE #Text VARCHAR(50) = ', 9132124, :::';
SELECT COALESCE(STUFF(#Text, 1, PATINDEX('%[A-z]%', #Text) - 1, ''), '');
This will output an empty string.
You could also use REPLACE.....
eg.
REPLACE( ' ,Your String with space comma', ' ,', '')
UPDATE dbo.Employee
SET
dbo.Employee.ContactName = replace(LEFT(ContactName, 2),', ','')
+ SUBSTRING (ContactName, 3, len(contactname))
where LEFT(ContactName, 2)=', '
This will only update where first two character contains ', '

deleting second comma in data

Ok so I have a table called PEOPLE that has a name column. In the name column is a name, but its totally a mess. For some reason its not listed such as last, first middle. It's sitting like last,first,middle and last first (and middle if there) are separated by a comma.. two commas if the person has a middle name.
example:
smith,steve
smith,steve,j
smith,ryan,tom
I'd like the second comma taken away (for parsing reason ) spaces put after existing first comma so the above would come out looking like:
smith, steve
smith, steve j
smith, ryan tom
Ultimately I'd like to be able to parse the names into first, middle, and last name fields, but that's for another post :_0. I appreciate any help.
thank you.
Drop table T1;
Create table T1(Name varchar(100));
Insert T1 Values
('smith,steve'),
('smith,steve,j'),
('smith,ryan,tom');
UPDATE T1
SET Name=
CASE CHARINDEX(',',name, CHARINDEX(',',name)+1) WHEN
0 THEN Name
ELSE
LEFT(name,CHARINDEX(',',name, CHARINDEX(',',name)+1)-1)+' ' +
RIGHT(name,LEN(Name)-CHARINDEX(',',name, CHARINDEX(',',name)+1))
END
Select * from T1
This seems to work. Not the most concise but avoids cursors.
DECLARE #people TABLE (name varchar(50))
INSERT INTO #people
SELECT 'smith,steve'
UNION
SELECT 'smith,steve,j'
UNION
SELECT 'smith,ryan,tom'
UNION
SELECT 'commaless'
SELECT name,
CASE
WHEN CHARINDEX(',',name) > 0 THEN
CASE
WHEN CHARINDEX(',',name,CHARINDEX(',',name) + 1) > 0 THEN
STUFF(STUFF(name, CHARINDEX(',',name,CHARINDEX(',',name) + 1), 1, ' '),CHARINDEX(',',name),1,', ')
ELSE
STUFF(name,CHARINDEX(',',name),1,', ')
END
ELSE name
END AS name2
FROM #people
Using a table function to split apart the names with a delimiter and for XML Path to stitch them back together, we can get what you're looking for! Hope this helps!
Declare #People table(FullName varchar(200))
Insert Into #People Values ('smith,steve')
Insert Into #People Values ('smith,steve,j')
Insert Into #People Values ('smith,ryan,tom')
Insert Into #People Values ('smith,john,joseph Jr')
Select p.*,stuff(fn.FullName,1,2,'') as ModifiedFullName
From #People p
Cross Apply (
select
Case When np.posID<=2 Then ', ' Else ' ' End+np.Val
From #People n
Cross Apply Custom.SplitValues(n.FullName,',') np
Where n.FullName=p.FullName
For XML Path('')
) fn(FullName)
Output:
ModifiedFullName
smith, steve
smith, steve j
smith, ryan tom
smith, john joseph Jr
SplitValues table function definition:
/*
This Function takes a delimited list of values and returns a table containing
each individual value and its position.
*/
CREATE FUNCTION [Custom].[SplitValues]
(
#List varchar(max)
, #Delimiter varchar(1)
)
RETURNS
#ValuesTable table
(
posID int
,val varchar(1000)
)
AS
BEGIN
WITH Cte AS
(
SELECT CAST('<v>' + REPLACE(#List, #Delimiter, '</v><v>') + '</v>' AS XML) AS val
)
INSERT #ValuesTable (posID,val)
SELECT row_number() over(Order By x) as posID, RTRIM(LTRIM(Split.x.value('.', 'VARCHAR(1000)'))) AS val
FROM Cte
CROSS APPLY val.nodes('/v') Split(x)
RETURN
END
GO
String manipulation in SQLServer, outside of writing your own User Defined Function, is limited but you can use the PARSENAME function for your purposes here. It takes a string, splits it on the period character, and returns the segment you specify.
Try this:
DECLARE #name VARCHAR(100) = 'smith,ryan,tom'
SELECT REVERSE(PARSENAME(REPLACE(REVERSE(#name), ',', '.'), 1)) + ', ' +
REVERSE(PARSENAME(REPLACE(REVERSE(#name), ',', '.'), 2)) +
COALESCE(' ' + REVERSE(PARSENAME(REPLACE(REVERSE(#name), ',', '.'), 3)), '')
Result: smith, ryan tom
If you set #name to 'smith,steve' instead, you'll get:
Result: smith, steve
Segment 1 actually gives you the last segment, segment 2 the second to last etc. Hence I've used REVERSE to get the order you want. In the case of 'steve,smith', segment 3 will be null, hence the COALESCE to add an empty string if that is the case. The REPLACE of course changes the commas to periods so that the split will work.
Note that this is a bit of a hack. PARSENAME will not work if there are more than four parts and this will fail if the name happens to contain a period. However if your data conforms to these limitations, hopefully it provides you with a solution.
Caveat: it sounds like your data may be inconsistently formatted. In that case, applying any automated treatment to it is going to be risky. However, you could try:
UPDATE people SET name = REPLACE(name, ',', ' ')
UPDATE people SET name = LEFT(name, CHARINDEX(' ', name)-1)+ ', '
+ RIGHT(name, LEN(name) - CHARINDEX(' ', name)
That'll work for the three examples you give. What it will do to the rest of your set is another question.
Here's an example with CHARINDEX() and SUBSTRING
WITH yourTable
AS
(
SELECT names
FROM
(
VALUES ('smith,steve'),('smith,steve,j'),('smith,ryan,tom')
) A(names)
)
SELECT names AS old,
CASE
WHEN comma > 0
THEN SUBSTRING(spaced_names,0,comma + 1) --before the comma
+ SUBSTRING(spaced_names,comma + 2,1000) --after the comma
ELSE spaced_names
END AS new
FROM yourTable
CROSS APPLY(SELECT CHARINDEX(',',names,CHARINDEX(',',names) + 1),REPLACE(names,',',', ')) AS CA(comma,spaced_names)

How to find more than 1 uppercase character

I'm running a series of SQL queries to find data that needs cleaning up. One of them I want to do is look for:
2 or more uppercase letters in a row
starting with a lowercase letter
space then a lowercase letter
For example my name should be "John Doe". I would want it to find "JOhn Doe" or "JOHN DOE" or "John doe", but I would not want it to find "John Doe" since that is formatted correctly.
I am using SQL Server 2008.
The key is to use a case-sensitive collation, i.e. Latin1_General_BIN*. You can then use a query with a LIKE expression like the following (SQL Fiddle demo):
select *
from foo
where name like '%[A-Z][A-Z]%' collate Latin1_General_BIN --two uppercase in a row
or name like '% [a-z]%' collate Latin1_General_BIN --space then lowercase
*As per How do I perform a case-sensitive search using LIKE?, apparently there is a "bug" in the Latin1_General_CS_AS collation where ranges like [A-Z] fail to be case sensitive. The solution is to use Latin1_General_BIN.
First, I think you should make a function that returns a proper name (sounds like you need one anyway). See here under the heading "Proper Casing a Persons Name". Then find the ones that don't match.
SELECT Id, Name, dbo.ProperCase(Name)
FROM MyTable
WHERE Name <> dbo.PoperCase(Name) collate Latin1_General_BIN
This will help you clean up the data and tweak the function to what you need.
You can use a regular expression. I'm not a SQL Server whiz, but you want to use RegexMatch. Something like this:
select columnName
from tableName
where dbo.RegexMatch( columnName,
N'[A-Z]\W[A-Z]' ) = 1
If your goal is to update your column to capitalize the first character of each word (in your case firstName and lastName) , you can use the following query.
Create a sample table with data
Declare #t table (Id int IDENTITY(1,1),Name varchar(50))
insert into #t (name)values ('john doe'),('lohn foe'),('tohnytty noe'),('gohnsdf fgedsfsdf')
Update query
UPDATE #t
SET name = UPPER(LEFT(SUBSTRING(Name, 1, CHARINDEX(' ', Name) - 1), 1)) + RIGHT(SUBSTRING(Name, 1, CHARINDEX(' ', Name) - 1), LEN(SUBSTRING(Name, 1, CHARINDEX(' ', Name) - 1)) - 1) +
' ' +
UPPER(LEFT(SUBSTRING(Name, CHARINDEX(' ', Name) + 1, 8000), 1)) + RIGHT(SUBSTRING(Name, CHARINDEX(' ', Name) + 1, 8000), LEN(SUBSTRING(Name, CHARINDEX(' ', Name) + 1, 8000)) - 1)
FROM #t
Output
SELECT * FROM #t
Id Name
1 John Doe
2 Lohn Foe
3 Tohnytty Noe
4 Gohnsdf Fgedsfsdf
I use this way:
;WITH yourTable AS(
SELECT 'John Doe' As name
UNION ALL SELECT 'JOhn Doe'
UNION ALL SELECT 'JOHN DOE'
UNION ALL SELECT 'John doe'
UNION ALL SELECT 'John DoE'
UNION ALL SELECT 'john Doe'
UNION ALL SELECT 'jOhn dOe'
UNION ALL SELECT 'jOHN dOE'
UNION ALL SELECT 'john doe'
)
SELECT name
FROM (
SELECT name,
LOWER(PARSENAME(REPLACE(name, ' ', '.'), 1)) part2,
LOWER(PARSENAME(REPLACE(name, ' ', '.'), 2)) part1
FROM yourTable) t
WHERE name COLLATE Latin1_General_BIN = UPPER(LEFT(part1,1)) + RIGHT(part1, LEN(part1) -1) +
' ' + UPPER(LEFT(part2,1)) + RIGHT(part2, LEN(part2) -1)
Note:
This will be good for just two parted names for more, it should improved.

parse lastname, firstname and truncate and caps

I have a field stores customer name all in one column: John, Dao. Names are stored as Lastname, FirstName.
What I need to do is list last name in CAPS, truncated at 10 characters, followed by first initial of first name (first initial Caps Letter). For example John, Dao needs to be displayed as JOHN D.
Try something like this...
DECLARE #FullName varchar(50) = 'Smithxxxxxxxxx, John';
SELECT UPPER(SUBSTRING(SUBSTRING(#FullName, 1, CHARINDEX(',', #FullName)-1), 1, 10) ) as LastName
, UPPER( LTRIM( SUBSTRING(#FullName, CHARINDEX(',', #FullName) +1, 2))) as FirstName
--Example 1
DECLARE #FullName VARCHAR(50) = 'Smithxxxxxxxxx, John';
SELECT UPPER(LEFT(#FullName,
CHARINDEX(',', #FullName) - 1)) AS LastName ,
UPPER(LEFT(REPLACE(RIGHT(#FullName,
LEN(#FullName)
- CHARINDEX(',',
#FullName) - 1),
', ', ''), 1)) AS FirstName
-------------------------------------
--Example 2
DECLARE #FullName VARCHAR(50) = 'Smithxxxxxxxxx, John';
SELECT UPPER(LEFT(#FullName,
CHARINDEX(',', #FullName) - 1)) AS LastName ,
UPPER(LEFT(REPLACE(REVERSE(LEFT(REVERSE(#FullName),
CHARINDEX(',',
REVERSE(#FullName)))),
', ', ''), 1)) AS FirstName
Here's an example in SQLite:
sqlite> create table customer(lastname string, firstname string);
sqlite> insert into customer values("VerylongNameIndeed", "alex");
sqlite> SELECT UPPER(SUBSTR(lastname, 1, 10)), UPPER(SUBSTR(firstname, 1, 1)) FROM customer;
The result: VERYLONGNA|A
EDIT: I've just realised that the names are both stored as a single column in the question, so here's an amended version of the above:
sqlite> create table customer(name string);
sqlite> insert into customer values("john, dao");
sqlite> insert into customer values("VeryLongName, alex");
sqlite> SELECT UPPER(SUBSTR(name, 1, MIN(10, INSTR(name, ",")-1))), UPPER(SUBSTR(name, INSTR(name, ",")+2, 1)) FROM customer;
The result:
JOHN|D
VERYLONGNA|A

Splitting value of a varchar column into two columns

If I have a column in which strings vary in length but they ALL have a slash \ within,
how can I SELECT to have one column display everything BEFORE the \ and another column displaying everything AFTER the \?
name column1 column2
DB5697\DEV DB5697 DEV
I have seen CHARINDEX and REVERSE on MSDN but haven't been able to put together a soltuion.
How can I best split a varchar/string column value into 2 columns in a result set in TSQL ?
what about using PARSENAME function in a tricky way?
USE tempdb;
GO
CREATE TABLE #names
(
id int NOT NULL PRIMARY KEY CLUSTERED
, name varchar(30) NOT NULL
);
GO
INSERT INTO #names (id, name)
VALUES
(1, 'DB5697\DEV'),
(2, 'DB5800\STG'),
(3, 'DB5900\PRD');
GO
SELECT
name
, PARSENAME(REPLACE(name, '\', '.'), 2) AS [Server]
, PARSENAME(REPLACE(name, '\', '.'), 1) AS [Instance]
FROM
#names;
GO
DROP TABLE #names;
GO
The PARSENAME function accepts 2 parameters and gets the name part of a fully qualified name. The second parameter is the part name enumerator.
Value 2 is for SCHEMA and 1 is for OBJECT.
So, with the REPLACE function the "\" char is replaced by "." in order to have a SCHEMA.OBJECT format of your SERVERNAME\INSTANCE values. Then, PARSENAME behave like having a simple object name in the string.
How about the following (SQL Fiddle):
SELECT m.name,
LEFT(m.name, CHARINDEX('\', m.name) - 1) AS column1,
RIGHT(m.name, LEN(m.name) - CHARINDEX('\', m.name)) AS column2
FROM MyTable m
How to handle strings with no \ in them (SQL Fiddle):
SELECT m.name,
CASE WHEN CHARINDEX('\', m.name) = 0 THEN ''
ELSE LEFT(m.name, CHARINDEX('\', m.name) - 1) END AS column1,
CASE WHEN CHARINDEX('\', m.name) = 0 THEN ''
ELSE RIGHT(m.name, LEN(m.name) - CHARINDEX('\', m.name)) END AS column2
FROM MyTable m;
You can use CHARINDEX to check for the character position of the splitter ('/') and use SUBSTRING to split the string.
However care has to be taken to ensure you handle records without splitters else you would invoke an error.
Also in the case where splitter is unavailable, decision has to be made as to which column the data should be mapped to. Here I am mapping data to FirstName and assigning NULL to LastName
DECLARE #TableBuyer TABLE (ID INT, FullName VARCHAR(100))
INSERT INTO #TableBuyer
SELECT '1','Bryan/Greenberg' UNION ALL
SELECT '2','Channing/Tatum' UNION ALL
SELECT '3','Paul/William' UNION ALL
SELECT '4','EricBana' UNION ALL
SELECT '5','James/Lafferty' UNION ALL
SELECT '6','Wentworth/Miller'
SELECT
CASE
WHEN CHARINDEX('/', FullName) > 0 THEN SUBSTRING(FullName, 1, CHARINDEX('/', FullName) - 1)
ELSE FullName
END AS FirstName
,
CASE
WHEN CHARINDEX('/', FullName) > 0 THEN SUBSTRING(FullName, CHARINDEX('/', FullName) + 1, LEN(FullName))
ELSE NULL
END AS LastName
FROM #TableBuyer;
DECLARE #TableBuyer TABLE (ID INT, FullName VARCHAR(100))
INSERT INTO #TableBuyer
SELECT '1','Bryan/Greenberg' UNION ALL
SELECT '2','Channing/Tatum' UNION ALL
SELECT '3','Paul/William' UNION ALL
SELECT '4','EricBana' UNION ALL
SELECT '5','James/Lafferty' UNION ALL
SELECT '6','Wentworth/Miller'
select left(FullName, len(FullName)-CHARINDEX('/', REVERSE(FullName))) as firstname,
substring(FullName, len(FullName)-CHARINDEX('/', REVERSE(FullName))+ 2, len(FullName)) as lastname
from #TableBuyer
OR
select left(FullName, len(FullName)-CHARINDEX('/', REVERSE(FullName))) as firstname,
RIGHT(FullName, len(FullName)-CHARINDEX('/', FullName)) as lastname
from #TableBuyer
There is no "simple" method. Something like this should work:
select left(col, charindex('\', col) - 1) as column1,
right(col, charindex('\', reverse(col)) - 1) as column2
You might need to double up on the backslash ('\\') to get it to work properly.