I have a bunch of rows that have a field called "name" that have values like this, delimited by a _:
ServerNumber_BrandNumber_BrandName_JobName
Sometimes, the job name will be spread out over two deliminations, like this:
ServerNumber_BrandNumber_BrandName_JobName_JobNamePart2
I want to break out each of those into their own field in a select statement like this:
SELECT
name[0] as ServerNumber,
name[1] as BrandNumber,
name[2] as BrandName,
name[3] as JobName
from table
If I do something like this it will work if job name is only part of one delmiter, but it will return nothing if it's using two:
REVERSE(PARSENAME(REPLACE(REVERSE(name), '_', '.'), 1))
How can I do all of this?
Working example
Declare #YourTable Table ([Name] varchar(150)) Insert Into #YourTable Values
('ServerNumber_BrandNumber_BrandName_JobName')
,('ServerNumber_BrandNumber_BrandName_JobName_JobNamePart2')
Select Pos1 = JSON_VALUE(JS,'$[0]')
,Pos2 = JSON_VALUE(JS,'$[1]')
,Pos3 = JSON_VALUE(JS,'$[2]')
,Pos4 = concat(JSON_VALUE(JS,'$[3]'),'_'+JSON_VALUE(JS,'$[4]'))
From #YourTable A
Cross Apply (values ('["'+replace(replace(string_escape([Name],'json'),' ','_'),'_','","')+'"]') ) B(JS)
Results
Pos1 Pos2 Pos3 Pos4
ServerNumber BrandNumber BrandName JobName
ServerNumber BrandNumber BrandName JobName_JobNamePart2
XML Approach (2012)
Select Pos1 = xDim.value('/x[1]','varchar(150)')
,Pos2 = xDim.value('/x[2]','varchar(150)')
,Pos3 = xDim.value('/x[3]','varchar(150)')
,Pos4 = concat(xDim.value('/x[4]','varchar(150)'),'_'+xDim.value('/x[5]','varchar(150)'))
From #YourTable A
Cross Apply ( values (cast('<x>' + replace((Select replace(NAME,'_','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml))) B(xDim)
Related
I have an AWS server name and I am trying to just get the domain name.
Here is an example of the server name:
SERVER1.SERVER2.US-WEST-5.RDS.AMAZONAWS.COM,59642
I just want to return:
US-WEST-5.RDS.AMAZONAWS.COM
I have tried using something similar to this:
But that is only for semi-colons. I know it is nested substrings and charindexes,
You can try this using SUBSTRING (Transact-SQL)
.
Returns part of a character, binary, text, or image expression in SQL Server.
Syntax
SUBSTRING ( expression ,start , length )
Here is the implementation.
SELECT SUBSTRING('SERVER1.SERVER2.US-WEST-5.RDS.AMAZONAWS.COM,59642',
1, CHARINDEX(',', 'SERVER1.SERVER2.US-WEST-5.RDS.AMAZONAWS.COM,59642') - 1)
AS FirstPart
Here is the live db<>fiddle demo.
Just another option. Perhaps a little overkill, but it demonstrates how you can parse a delimited string into columns.
Example
Declare #YourTable table (ID int,SomeCol varchar(500))
Insert Into #YourTable values
(1,'SERVER1.SERVER2.US-WEST-5.RDS.AMAZONAWS.COM,59642')
,(2,'SERVER1.SERVER2.US-WEST-6.RDS.AMAZONAWS.COM') -- note no trailing ,
,(2,'SERVER1.SERVER2.US-WEST-6.RDS.DEV.AMAZONAWS.COM') -- note extra DEV ,
Select A.ID
,NewStr = concat(pos3,'.'+pos4,'.'+pos5,'.'+pos6,'.'+pos7,'.'+pos8,'.'+pos9)
From #YourTable A
Cross Apply ( values ( left(SomeCol,charindex(',',SomeCol+',')-1 ))) B(CleanString) -- Removes Trailing ,####
Cross Apply ( -- Parses CleanString on .
Select Pos1 = xDim.value('/x[1]','varchar(max)') -- Can be removed
,Pos2 = xDim.value('/x[2]','varchar(max)') -- Can be removed
,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)')
,Pos7 = xDim.value('/x[7]','varchar(max)')
,Pos8 = xDim.value('/x[8]','varchar(max)')
,Pos9 = xDim.value('/x[9]','varchar(max)')
From ( values (cast('<x>' + replace(CleanString,'.','</x><x>')+'</x>' as xml))) as A(xDim)
) C
Returns
ID NewStr
1 US-WEST-5.RDS.AMAZONAWS.COM
2 US-WEST-6.RDS.AMAZONAWS.COM
2 US-WEST-6.RDS.DEV.AMAZONAWS.COM
I am trying to split a string in SQL on the space delimiter. The number of spaces changes, so there can be values for 4 or 5 columns. I am trying using CHARINDEX and SUBSTRING, but can't get past the first delimiter.
Example:
input would be '444 Addison Avenue SA 5222'
To split into columns, you could use a little XML in concert with a CROSS APPLY
Example
Declare #YourTable Table ([SomeCol] varchar(50))
Insert Into #YourTable Values
('444 Addison Avenue SA 5222')
,('1 Washington Square')
Select A.*
,B.*
From #YourTable A
Cross Apply (
Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
From (Select Cast('<x>' + replace((Select replace([SomeCol],' ','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml) as xDim) as A
) B
Returns
You can achieve the same result only with XML-based splitting:
DECLARE #tmp TABLE ([Address] varchar(50))
INSERT INTO #tmp VALUES ('444 Addison Avenue SA 5222'),('1 Washington Square')
SELECT T.[Address]
,AddressElements.value(N'/x[1]','varchar(max)') AS Element_1
,AddressElements.value(N'/x[2]','varchar(max)') AS Element_2
,AddressElements.value(N'/x[3]','varchar(max)') AS Element_3
,AddressElements.value(N'/x[4]','varchar(max)') AS Element_4
,AddressElements.value(N'/x[5]','varchar(max)') AS Element_5
FROM (
SELECT [Address]
,CAST('<x>' + REPLACE([Address],' ','</x><x>') + '</x>' AS XML) AS AddressElements
FROM #tmp
) T
Results:
I have an email column with 3-4 emails in each row which i want to split into one email per column:
Current columns looks like this:
Email_column
1. drone#gmail.com bob#yahoo.com drake#gmail.com
Expected output should be:
Email_1 Email_2 Email_3
1. drone#email.com bob#yahoo.com drake#gmail.com
With a CROSS APPLY and a little XML
Example
Declare #YourTable table (ID int,Email_column varchar(max))
Insert Into #YourTable values
(1,'drone#gmail.com bob#yahoo.com drake#gmail.com')
Select A.ID
,B.*
From #YourTable A
Cross Apply (
Select Pos1 = n.value('/x[1]','varchar(max)')
,Pos2 = n.value('/x[2]','varchar(max)')
,Pos3 = n.value('/x[3]','varchar(max)')
,Pos4 = n.value('/x[4]','varchar(max)')
From (Select Cast('<x>' + replace(A.Email_column,' ','</x><x>')+'</x>' as xml) as n) X
) B
Returns
ID Pos1 Pos2 Pos3 Pos4
1 drone#gmail.com bob#yahoo.com drake#gmail.com NULL
There has been questions related to this asked, but I have not gotten the solution I am need of.
The string(s) I am trying to split up look like this:
/Dev/act/billing
or
/ST/recManage/prod/form
The issue I have is the first '/' giving me problems when I try and do things with LEFT/RIGHT/SUBSTRING/CHARINDEX. It messes up counts and stopping at the delimiter. Also, it is important to note that the number of delimiters changes. So I want to find a way to split it up so I can get every possible substring.
RIGHT(c3.Path,CHARINDEX('/', REVERSE(c3.Path))-1) AS LastPath
This has gotten me the last part of the string. I have messed with other things ilke:
SUBSTRING(c3.Path,CHARINDEX('/',c3.Path,(CHARINDEX('/',c3.Path)+1))+1,len(c3.Path)),
This gets everything after the second '/'
I have also messed with XML and
SET #delimiter='/'
;WITH CTE AS
(SELECT CAST('<M>' + REPLACE([Path], #delimiter , '</M><M>') + '</M>' AS XML)
AS [Type XML]
FROM [Rpts].[dbo].[Cata]
)
,
CTE2 as (Select [Type XML].value('/M[2]', 'varchar(50)') As FirstPath from CTE)
Then doing: CTE2.FirstPath to get the result. But this then gives NULL
I am not on SQL 2016 so I cannot use SPLIT_STRING.
Thank you
Try this:
DECLARE #mockup TABLE(ID INT IDENTITY,YourString VARCHAR(MAX));
INSERT INTO #mockup VALUES('/Dev/act/billing'),('/ST/recManage/prod/form');
SELECT m.ID
,B.part.value(N'text()[1]',N'nvarchar(max)')
FROM #mockup AS m
OUTER APPLY(SELECT CAST('<x>' + REPLACE(m.YourString,'/','</x><x>') + '</x>' AS XML)) AS A(Casted)
OUTER APPLY A.Casted.nodes(N'/x[text()]') AS B(part);
This approach is save as long as you do not have forbidden characters in your string (namely <, > and &). If you need this, just call in, it is possible to solve.
Using .nodes() with the XQuery predicat [text()] will ommit all rows with no value...
The result
ID Part
---------
1 Dev
1 act
1 billing
2 ST
2 recManage
2 prod
2 form
Without going dynamic, and if you have a limited (or max) number of columns, perhaps something like this:
The replace() in the Cross Apply assumes the strings begins with a '/'
(Easy to expand or contract ... the pattern is pretty clear)
Example
Declare #YourTable table (ID int,[Path] varchar(max))
Insert Into #YourTable values
(1,'/Dev/act/billing')
,(2,'/ST/recManage/prod/form')
Select A.ID
,B.*
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)')
,Pos7 = xDim.value('/x[7]','varchar(max)')
,Pos8 = xDim.value('/x[8]','varchar(max)')
,Pos9 = xDim.value('/x[9]','varchar(max)')
From (Select Cast('<x>' + replace(substring(A.Path,2,len(A.Path)),'/','</x><x>')+'</x>' as xml) as xDim) as A
) B
Returns
EDIT - Slightly Simplified Version
Notice the staggard Pos1 and /x[2]
Select A.ID
,Pos1 = xDim.value('/x[2]','varchar(max)')
,Pos2 = xDim.value('/x[3]','varchar(max)')
,Pos3 = xDim.value('/x[4]','varchar(max)')
,Pos4 = xDim.value('/x[5]','varchar(max)')
,Pos5 = xDim.value('/x[6]','varchar(max)')
From #YourTable A
Cross Apply ( Select Cast('<x>' + replace(A.Path,'/','</x><x>')+'</x>' as xml) ) B (xDim)
R/005/2016-17
This varchar value i have in a table, i need to add 1 to 005.
i need output R/006/2016-17 for the next entry
How can i split the string and add one.
Your table demonstrates just how bad things can be when you don't properly normalize your data. But you can do this using some string manipulation. I would strongly urge you to split this into the appropriate columns instead of keeping this all crammed together.
This code will produce the desired output based on your sample data.
declare #Something varchar(20) = 'R/005/2016-17'
select parsename(replace(#Something, '/', '.'), 3) + '/' + right('000' + convert(varchar(3), convert(int, parsename(replace(#Something, '/', '.'), 2)) + 1), 3) + '/' + parsename(replace(#Something, '/', '.'), 1)
If you don't have ParseName(), I have a TVF which may help. If you can't use the UDF, the logic is easily ported into the CROSS APPLY
Declare #YourTable table (ID int,String varchar(max))
Insert Into #YourTable values
(1,'R/005/2016-17'),
(2,'A/119/2016-18')
Update #YourTable
Set String = Pos1+'/'+right('000000'+cast(cast(Pos2 as int)+1 as varchar(25)),len(Pos2))+'/'+Pos3
From #YourTable A
Cross Apply [dbo].[udf-Str-Parse-Row](A.String,'/') B
Select * from #YourTable
The Update Table
ID String
1 R/006/2016-17
2 A/120/2016-18
The UDF if Needed
CREATE FUNCTION [dbo].[udf-Str-Parse-Row] (#String varchar(max),#Delimiter varchar(10))
Returns Table
As
Return (
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)')
,Pos7 = xDim.value('/x[7]','varchar(max)')
,Pos8 = xDim.value('/x[8]','varchar(max)')
,Pos9 = xDim.value('/x[9]','varchar(max)')
From (Select Cast('<x>' + Replace(#String,#Delimiter,'</x><x>')+'</x>' as XML) as xDim) A
)
--Select * from [dbo].[udf-Str-Parse-Row]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-Row]('John Cappelletti',' ')
You can use Computed Columns when create table for this type case.
Eg:-
[EmployeeNo] AS ([PreFix]+ RIGHT('0000000' + CAST(Id AS VARCHAR(7)), 7)) PERSISTED,
https://msdn.microsoft.com/en-us/library/ms188300.aspx