Splitting value of a varchar column into two columns - sql

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.

Related

Extract substring from a string in SQL Server

I need to extract a part of substring from string which follows as per below.
YY_12.Yellow
ABC_WSA.Thisone_A
SS_4MON.DHHE_A_A
I need to extract the string as per below
Yellow
Thisone
DHHE
You could use something like this:
declare #tbl table (col nvarchar(100));
insert #tbl values ('YY_12.Yellow'), ('ABC_WSA.Thisone_A'), ('SS_4MON.DHHE_A_A')
select *
, charindex('_', col2, 0)
, left(col2,
case
when charindex('_', col2, 0) - 1 > 0
then charindex('_', col2, 0) - 1
else len(col2)
end) [result]
from (
select col
, substring(col, charindex('.', col, 0) + 1, len(col)) [col2]
from #tbl ) rs
I'm going to leave the full code so as you can hopefully understand what I did.
First identify and remove everything up to the dot "." (in the [col2] column in the nested SELECT)
Then I nest that SELECT so I can apply a new logic much easier on the result column from the first SELECT from which I only keep everything up to the underscore "_"
The final result is stored in the [result] column
Try this:
CREATE TABLE app (info varchar(20))
INSERT INTO app VALUES
('YY_12.Yellow'),
('ABC_WSA.Thisone_A'),
('SS_4MON.DHHE_A_A'),
('testnopoint')
SELECT
CASE
WHEN CHARINDEX('.', info) > 0 THEN
CASE
WHEN CHARINDEX('_', info, CHARINDEX('.', info) + 1) > 0 THEN
SUBSTRING(info, CHARINDEX('.', info) + 1, CHARINDEX('_', info, CHARINDEX('.', info) + 1) - CHARINDEX('.', info) - 1)
ELSE
SUBSTRING(info, CHARINDEX('.', info) + 1, LEN(info))
END
END
FROM app
My query, if . is not present returns NULL, if you want returns all string remove the CASE statement
Go on SqlFiddle
You could also try with parsename() function available from SQL Server 2012
select Name, left(parsename(Name,1),
case when charindex('_', parsename(Name,1)) > 0
then charindex('_', parsename(Name,1))-1
else len(parsename(Name,1))
end) [ExtrectedName] from table
This assumes you have always . in your string to read the name after .
Result :
Name ExtrectedName
YY_12.Yellow Yellow
ABC_WSA.Thisone_A Thisone
SS_4MON.DHHE_A_A DHHE
Try this, used STUFF here
SELECT LEFT(STUFF(col,1,CHARINDEX('.',col),''),
CHARINDEX('_',STUFF(col,1,CHARINDEX('.',col),'')+'_')-1
)
FROM #table
Output:-
Yellow
Thisone
DHHE

Select only characters in SQL

I have strings in a database like this:
firstname.lastname#email.com
And I only need the characters that appear after the # symbol and before (.) symbol i.e. (email) from the above example
I am trying to find a simple way to do this in SQL.
Do this:
use [your_db_name];
go
create table dbo.test
(
string varchar(max) null
)
insert into dbo.test values ('firstname.lastname#email.com')
select
string,
substring(
string,
charindex('#', string, 0) + 1,
charindex('.', string, charindex('#', string, 0)) - charindex('#', string, 0) - 1
) as you_need
from dbo.test
String manipulations are such a pain in SQL Server. Here is one method:
select t.*,
left(en.emailname, charindex('.', en.emailname + '.') - 1)
from t outer apply
(select stuff(email, 1, charindex('#', email + '#'), '') as emailname) en;
That that in the charindex() calls, the character being searched for is placed at the end of the string. This allows the code to work even for malformed emails -- it returns an empty string when the email is not of the form '%#%.%'.
DECLARE #col char(200)
set #col = 'firstname.lastname#email.com'
SELECT SUBSTRING(#col, LEN(LEFT(#col, CHARINDEX ('#', #col))) + 1, LEN(#col) - LEN(LEFT(#col, CHARINDEX ('#', #col))) - LEN(RIGHT(#col, LEN(#col) - CHARINDEX ('.', #col))) - 4);
DECLARE #str varchar(50) = 'firstname.lastname#email.com';
SELECT LEFT(
RIGHT(#str, LEN(#str) - CHARINDEX('#', #str))
,CHARINDEX('.', RIGHT(#str, LEN(#str) - CHARINDEX('#', #str))
) - 1) AS OUTPUT
Above query gives only domain-name from Email. The query can be applied for column in a table
Try This:-
DECLARE #Text varchar(100)
SET #Text = 'firstname.lastname#email.com'
SELECT SUBSTRING(STUFF(#Text, 1, CHARINDEX('#',#Text), ''), 0,
CHARINDEX('.', STUFF(#Text, 1, CHARINDEX('#',#Text), '')))
Result:-
email
DECLARE #myStr varchar(100) = 'firstname.lastname#email.com'
SELECT
SUBSTRING(SUBSTRING(#myStr,CHARINDEX('#',#myStr)+1,LEN(#myStr)-CHARINDEX('#',#myStr)+1),0,CHARINDEX('.',SUBSTRING(#myStr,CHARINDEX('#',#myStr)+1,LEN(#myStr)-CHARINDEX('#',#myStr)+1)))
That can be useful but I really recommend you to build user defined function in C#/Visaul basic they could be much more faster that this.
Using charindex, len and reverse to search for the positions of the # and the last dot.
And substring to get the name based on those positions:
create table test (id int identity(1,1), email varchar(60));
insert into test (email) values
('jane.doe#email.com'),
('not an email'),
('#invalid.email.xxx'),
('john.doe#longer.domainname.net');
select *,
(case
when email like '[a-z]%#%.%'
then substring(email,
charindex('#',email)+1,
len(email) - charindex('#',email) - charindex('.',reverse(email))
)
end) as email_domain_without_extension
from test;
The CASE WHEN is used to return NULL when it's not an email (instead of an empty string).

first letters in firstname and lastname uppercase

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

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.

Tricky SQL query requiring search for contains

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