How to split multiple strings and insert SQL Server FN_SplitStr - sql

I have 2 strings and one integer:
#categoryID int = 163,
#Ids nvarchar(2000) = '1,2,3',
#Names nvarchar(2000) = 'Bob,Joe,Alex'
I need to select 3 columns 3 rows; The most accomplished is 3 rows 2 columns:
select #categoryID,items from FN_SplitStr(#Ids,',')
resulting:
163,1
163,2
163,3
But I can't figure out how to split both strings.
I tried many ways like:
select #categoryID,items from FN_SplitStr((#Ids,#Names),',')
select #categoryID,items from FN_SplitStr(#Ids,','),items from FN_SplitStr(#Names,',')
EXPECTED OUTPUT:
163,1,Bob
163,2,Joe
163,3,Alex
NOTE1: I looked over tens of questions the most similar is:
How to split string and insert values into table in SQL Server AND SQL Server : split multiple strings into one row each but this question is different.
NOTE2: FN_SplitStr is a function for spliting strings in SQL. And I'm trying to create a stored procedure.

Based on your expected output, you have to use cross apply twice and then create some sort of ranking to make sure that you are getting the right value. As IDs and Names don't seem to have any relationship cross apply will create multiple rows (when you split the string to Names and ID)
There might be better way but this also gives your expected output. You can change this string split to your local function.
1st Dense rank is to make sure that we get three unique names and 2nd dense rank is the rank within the name based on order by with ID and outside of the sub query you have to do some comparison to get only 3 rows.
Declare #categoryID int = 163,
#Ids nvarchar(2000) = '1,2,3',
#Names nvarchar(2000) = 'Bob,Joe,Alex'
select ConcatenatedValue, CategoryID, IDs, Names from (
select concat(#categoryID,',',a.value,',',b.value) ConcatenatedValue, #categoryID CategoryID,
A.value as IDs, b.value as Names , DENSE_RANK() over (order by b.value) as Rn,
DENSE_RANK() over (partition by b.value order by a.value) as Ranked
from string_split(#IDs,',') a
cross apply string_split(#names,',') B ) t
where Rn - Ranked = 0
Output:

Inside your stored procedure do a string split of #Ids and insert into #temp1 table with an identity(1,1) column rowed. You will get:
163,1,1
163,2,2
163,3,3
Then do the second string split of #Names and insert into #temp2 table with an identity(1,1) column rowed. You will get:
Bob,1
Joe,2
Alex,3
You can then do an inner join with #temp1 and #temp2 on #temp1.rowid = #temp2.rowid and get:
163,1,Bob
163,2,Joe
163,3,Alex
I hope this solves your problem.

You can do this with a recursive CTE:
with cte as (
select #categoryId as categoryId,
convert(varchar(max), left(#ids, charindex(',', #ids + ',') - 1)) as id,
convert(varchar(max), left(#names, charindex(',', #names + ',') - 1)) as name,
convert(varchar(max), stuff(#ids, 1, charindex(',', #ids + ','), '')) as rest_ids,
convert(varchar(max), stuff(#names, 1, charindex(',', #names + ','), '')) as rest_names
union all
select categoryId,
convert(varchar(max), left(rest_ids, charindex(',', rest_ids + ',') - 1)) as id,
convert(varchar(max), left(rest_names, charindex(',', rest_names + ',') - 1)) as name,
convert(varchar(max), stuff(rest_ids, 1, charindex(',', rest_ids + ','), '')) as rest_ids,
convert(varchar(max), stuff(rest_names, 1, charindex(',', rest_names + ','), '')) as rest_names
from cte
where rest_ids <> ''
)
select categoryid, id, name
from cte;
Here is a db<>fiddle.

You need to split CSV value with record number. For that you need to use ROW_NUMBER() function to generate record wise unique ID as column like "RID", while you split CSV columns in row.
You can use table value split function or XML as used below.
Please check this let us know your solution is found or not.
DECLARE
#categoryID int = 163,
#Ids nvarchar(2000) = '1,2,3',
#Names nvarchar(2000) = 'Bob,Joe,Alex'
SELECT
#categoryID AS categoryID,
q.Id,
w.Names
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY f.value('.','VARCHAR(10)')) AS RID,
f.value('.','VARCHAR(10)') AS Id
FROM
(
SELECT
CAST('<a>' + REPLACE(#Ids,',','</a><a>') + '</a>' AS XML) AS idXML
) x
CROSS APPLY x.idXML.nodes('a') AS e(f)
) q
INNER JOIN
(
SELECT
ROW_NUMBER() OVER (ORDER BY h.value('.','VARCHAR(10)')) AS RID,
h.value('.','VARCHAR(10)') AS Names
FROM
(
SELECT
CAST('<a>' + REPLACE(#Names,',','</a><a>') + '</a>' AS XML) AS namesXML
) y
CROSS APPLY y.namesXML.nodes('a') AS g(h)
) w ON w.RID = q.RID

Related

Joining sql tables with no common columns without ordering

I have my data in a form of 2 coma separated strings
DECLARE #ids nvarchar(max) = '1,2,3'
DECLARE #guids nvarchar(max) =
'0000000-0001-0000-0000-000000000000,
`0000000-0022-0000-0000-000000000000`,
`0000000-0013-0000-0000-000000000000'`
I need them in a table as separate columns based on their position in the string
Table1
| Id | Guid |
| 1 | 0000000-0001-0000-0000-000000000000 |
| 2 | 0000000-0022-0000-0000-000000000000 |
| 3 | 0000000-0013-0000-0000-000000000000 |
I can split both strings into separate tables by using
DECLARE #split_ids
(value nvarchar(max))
DECLARE #xml xml
SET #xml = N'<root><r>' + replace(#ids, ',' ,'</r><r>') + '</r></root>'
INSERT INTO #split_ids(Value)
SELECT r.value('.','nvarchar(max)')
FROM #xml.nodes('//root/r') as records(r)
I've tried
SELECT t1.*, t2.*
FROM (SELECT t1.*, row_number() OVER (ORDER BY [Value]) as seqnum
from cte_Ids t1
) t1 FULL OUTER JOIN
(SELECT t2.*, row_number() OVER (ORDER BY [Value]) as seqnum
from cte_barcodes t2
) t2
ON t1.seqnum = t2.seqnum;
But that orders the tables by Value and my data is random and can't be ordered.
Is there a way of joining tables based on their row numbers without ordering them first?
Or is there another way of inserting data from a string to a table?
You do not need to split and/or insert the input data into separate tables. In this situation you simply need to parse the input strings and get the substrings and their ordinal positions (an XML-based approach or a splitter function are possible solutions).
But if you use SQL Server 2016+, a JSON-based approach is also an option. The idea is to transform the strings into valid JSON arrays (1,2,3 into [1,2,3]), parse the arrays with OPENJSON() and join the tables returned from OPENJSON() calls. As is explained in the documentation, the columns that OPENJSON() function returns (when the default schema is used) are key, value and type and in case of JSON array, the key column holds the index of the element in the specified array.
DECLARE #ids nvarchar(max) = N'1,2,3'
DECLARE #guids nvarchar(max) = N'0000000-0001-0000-0000-000000000000,0000000-0022-0000-0000-000000000000,0000000-0013-0000-0000-000000000000'
SELECT j1.[value] AS Id, j2.[value] AS Guid
FROM OPENJSON(CONCAT('[', #ids, ']')) j1
JOIN OPENJSON(CONCAT('["', REPLACE(#guids, ',', '","'), '"]')) j2 ON j1.[key] = j2.[key]
Result:
Id Guid
1 0000000-0001-0000-0000-000000000000
2 0000000-0022-0000-0000-000000000000
3 0000000-0013-0000-0000-000000000000
You need row numbering over initial order, this means that you should use some constant expression in window function order_by clause.
SQL server does not allow use constants directly, but over(order_by (select 1)) is allowed:
SELECT t1.*, t2.*
FROM (SELECT t1.*, row_number() OVER (ORDER BY (select 1)) as seqnum
from cte_Ids t1
) t1 FULL OUTER JOIN
(SELECT t2.*, row_number() OVER (ORDER BY (select 1)) as seqnum
from cte_barcodes t2
) t2
ON t1.seqnum = t2.seqnum;
Note that this doesn't guarantee initial order (it will be unspecified), but often it behaves correctly :)
One of solutions is to parse your comma separated values in a loop (using WHILE) from both variables. Then you could insert those extracted in the same iteration values at once as one row to a table.
One solution uses recursive CTEs:
with cte as (
select cast(null as nvarchar(max)) as id, cast(null as nvarchar(max)) as guid, #ids + ',' as rest_ids, #guids + ',' as rest_guids, 0 as lev
union all
select left(rest_ids, charindex(',', rest_ids) - 1),
left(rest_guids, charindex(',', rest_guids) - 1),
stuff(rest_ids, 1, charindex(',', rest_ids), ''),
stuff(rest_guids, 1, charindex(',', rest_guids), ''),
lev + 1
from cte
where rest_ids <> ''
)
select id, guid
from cte
where lev > 0;
Here is a db<>fiddle.

Add character in front and at the end of each character

In SQL I want to add 0 in front and , at the end of each character.
Example: A30F1 -> 0A,03,00,0F,01
I don't want to use cursor if possible.
Thanks!
EIDT:
I apologize for not asking the most appropriate question at the beginning.
In short, I have a table and for each value in the column name I have to convert it to the desired format. For example, we have a #Temp table:
CREATE TABLE #Temp (id INT, name VARCHAR(25))
INSERT INTO #Temp VALUES (1, 'A30F1'), (2, 'B51R9'), (3, 'L1721')
SELECT * FROM #Temp
One method would be to use a Tally to split the string into it's individual characters, and then use concatenation to add the 0 to the start, and STRING_AGG to comma delimit the results:
DECLARE #YourValue varchar(5) = 'A30F1';
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (LEN(#YourValue))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2) --Up to 100 characters, add more cross joins for more characters
SELECT STRING_AGG(CONCAT('0',SS.C),',') WITHIN GROUP (ORDER BY T.I) AS NewString
FROM (VALUES(#YourValue))V(YourValue)
CROSS JOIN Tally T
CROSS APPLY (VALUES(SUBSTRING(V.YourValue,T.I,1)))SS(C);
It appears this is meant to be against a table, not a single value. This needs, however, very few changes to work against a table:
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (SELECT MAX(LEN(YourColumn)) FROM dbo.YourTable)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2) --Up to 100 characters, add more cross joins for more characters
SELECT STRING_AGG(CONCAT('0',SS.C),',') WITHIN GROUP (ORDER BY T.I) AS NewString
FROM dbo.YourTable YT
JOIN Tally T ON LEN(YT.YourColumn) >= T.I
CROSS APPLY (VALUES(SUBSTRING(YT.YourColumn,T.I,1)))SS(C)
GROUP BY YT.YourColumn;
db<>fiddle
I solved the simplest possible with a few variables, WHILE and SUBSTRING
DECLARE #var VARCHAR(20) = 'A30F1', #i INT = 1, #res NVARCHAR(20)
WHILE (#i <= LEN(#var))
BEGIN
SET #res = #res + '0' + SUBSTRING(#var, #i, 1) + ','
SET #i = #i + 1
END
SELECT LEFT(#res, LEN(#res) - 1) output
Check demo on DB<>FIDDLE.
Original answer:
A recursive CTE and a STRING_AGG() call is also an option (SQL Server 2017+ is needed):
DECLARE #text varchar(max) = 'A30F1';
WITH rCTE AS
(
SELECT 1 AS CharacterPosition, SUBSTRING(#text, 1, 1) AS Character
UNION ALL
SELECT CharacterPosition + 1, SUBSTRING(#text, CharacterPosition + 1, 1)
FROM rCTE
WHERE CharacterPosition < LEN(#text)
)
SELECT STRING_AGG('0' + Character, ',') WITHIN GROUP (ORDER BY CharacterPosition)
FROM rCTE
OPTION (MAXRECURSION 0);
Update:
You need a different statement, if the names are stored in a table, again using recursion and STRING_AGG():
Table:
CREATE TABLE #Temp (id INT, name VARCHAR(25))
INSERT INTO #Temp VALUES (1, 'A30F1'), (2, 'B51R9'), (3, 'L1721')
Statement:
; WITH rCTE AS (
SELECT
t.id AS id,
LEFT(t.name, 1) AS Character,
STUFF(t.name, 1, 1, '') AS CharactersRemaining,
1 AS CharacterPosition
FROM #Temp t
UNION ALL
SELECT
r.id,
LEFT(r.CharactersRemaining, 1),
STUFF(r.CharactersRemaining, 1, 1, ''),
CharacterPosition + 1
FROM rCTE r
WHERE LEN(r.CharactersRemaining) > 0
)
SELECT
id,
STRING_AGG('0' + Character, ',') WITHIN GROUP (ORDER BY CharacterPosition) AS name
FROM rCTE
GROUP BY id
OPTION (MAXRECURSION 0);
Result:
id name
1 0A,03,00,0F,01
2 0B,05,01,0R,09
3 0L,01,07,02,01
If you are only applying this to English alphabet characters and digits as in your example you could do this.
CREATE TABLE #Temp (id INT, name VARCHAR(25))
INSERT INTO #Temp VALUES (1, 'A30F1'), (2, 'B51R9'), (3, 'L1721'), (4, 'A')
SELECT SUBSTRING(REPLACE(
0x00 + CAST(CAST(name AS NVARCHAR(25)) AS BINARY(50)), CHAR(0), '0,')
, 3
, LEN(name) * 3 - 1)
FROM #Temp
returns
0A,03,00,0F,01
0B,05,01,0R,09
0L,01,07,02,01
0A
This takes advantage of the fact that the binary representation of the nvarchar and varchar is the same for this limited character set except for padding out with 0x00
'A30F1' -> 0x4133304631
N'A30F1' -> 0x41003300300046003100

Order Concatenated field

I have a field which is a concatenation of single letters. I am trying to order these strings within a view. These values can't be hard coded as there are too many. Is someone able to provide some guidance on the function to use to achieve the desired output below? I am using MSSQL.
Current output
CustID | Code
123 | BCA
Desired output
CustID | Code
123 | ABC
I have tried using a UDF
CREATE FUNCTION [dbo].[Alphaorder] (#str VARCHAR(50))
returns VARCHAR(50)
BEGIN
DECLARE #len INT,
#cnt INT =1,
#str1 VARCHAR(50)='',
#output VARCHAR(50)=''
SELECT #len = Len(#str)
WHILE #cnt <= #len
BEGIN
SELECT #str1 += Substring(#str, #cnt, 1) + ','
SET #cnt+=1
END
SELECT #str1 = LEFT(#str1, Len(#str1) - 1)
SELECT #output += Sp_data
FROM (SELECT Split.a.value('.', 'VARCHAR(100)') Sp_data
FROM (SELECT Cast ('<M>' + Replace(#str1, ',', '</M><M>') + '</M>' AS XML) AS Data) AS A
CROSS APPLY Data.nodes ('/M') AS Split(a)) A
ORDER BY Sp_data
RETURN #output
END
This works when calling one field
ie.
Select CustID, dbo.alphaorder(Code)
from dbo.source
where custid = 123
however when i try to apply this to top(10) i receive the error
"Invalid length parameter passed to the LEFT or SUBSTRING function."
Keeping in mind my source has ~4million records, is this still the best solution?
Unfortunately i am not able to normalize the data into a separate table with records for each Code.
This doesn't rely on a id column to join with itself, performance is almost as fast
as the answer by #Shnugo:
SELECT
CustID,
(
SELECT
chr
FROM
(SELECT TOP(LEN(Code))
SUBSTRING(Code,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)),1)
FROM sys.messages) A(Chr)
ORDER by chr
FOR XML PATH(''), type).value('.', 'varchar(max)'
) As CODE
FROM
source t
First of all: Avoid loops...
You can try this:
DECLARE #tbl TABLE(ID INT IDENTITY, YourString VARCHAR(100));
INSERT INTO #tbl VALUES ('ABC')
,('JSKEzXO')
,('QKEvYUJMKRC');
--the cte will create a list of all your strings separated in single characters.
--You can check the output with a simple SELECT * FROM SeparatedCharacters instead of the actual SELECT
WITH SeparatedCharacters AS
(
SELECT *
FROM #tbl
CROSS APPLY
(SELECT TOP(LEN(YourString)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) A(Nmbr)
CROSS APPLY
(SELECT SUBSTRING(YourString,Nmbr,1))B(Chr)
)
SELECT ID,YourString
,(
SELECT Chr As [*]
FROM SeparatedCharacters sc1
WHERE sc1.ID=t.ID
ORDER BY sc1.Chr
FOR XML PATH(''),TYPE
).value('.','nvarchar(max)') AS Sorted
FROM #tbl t;
The result
ID YourString Sorted
1 ABC ABC
2 JSKEzXO EJKOSXz
3 QKEvYUJMKRC CEJKKMQRUvY
The idea in short
The trick is the first CROSS APPLY. This will create a tally on-the-fly. You will get a resultset with numbers from 1 to n where n is the length of the current string.
The second apply uses this number to get each character one-by-one using SUBSTRING().
The outer SELECT calls from the orginal table, which means one-row-per-ID and use a correalted sub-query to fetch all related characters. They will be sorted and re-concatenated using FOR XML. You might add DISTINCT in order to avoid repeating characters.
That's it :-)
Hint: SQL-Server 2017+
With version v2017 there's the new function STRING_AGG(). This would make the re-concatenation very easy:
WITH SeparatedCharacters AS
(
SELECT *
FROM #tbl
CROSS APPLY
(SELECT TOP(LEN(YourString)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) A(Nmbr)
CROSS APPLY
(SELECT SUBSTRING(YourString,Nmbr,1))B(Chr)
)
SELECT ID,YourString
,STRING_AGG(sc.Chr,'') WITHIN GROUP(ORDER BY sc.Chr) AS Sorted
FROM SeparatedCharacters sc
GROUP BY ID,YourString;
Considering your table having good amount of rows (~4 Million), I would suggest you to create a persisted calculated field in the table, to store these values. As calculating these values at run time in a view, will lead to performance problems.
If you are not able to normalize, add this as a denormalized column to the existing table.
I think the error you are getting could be due to empty codes.
If LEN(#str) = 0
BEGIN
SET #output = ''
END
ELSE
BEGIN
... EXISTING CODE BLOCK ...
END
I can suggest to split string into its characters using referred SQL function.
Then you can concatenate string back, this time ordered alphabetically.
Are you using SQL Server 2017? Because with SQL Server 2017, you can use SQL String_Agg string aggregation function to concatenate characters splitted in an ordered way as follows
select
t.CustId, string_agg(strval, '') within GROUP (order by strval)
from CharacterTable t
cross apply dbo.SPLIT(t.code) s
where strval is not null
group by CustId
order by CustId
If you are not working on SQL2017, then you can follow below structure using SQL XML PATH for concatenation in SQL
select
CustId,
STUFF(
(
SELECT
'' + strval
from CharacterTable ct
cross apply dbo.SPLIT(t.code) s
where strval is not null
and t.CustId = ct.CustId
order by strval
FOR XML PATH('')
), 1, 0, ''
) As concatenated_string
from CharacterTable t
order by CustId

SQL Server split string and access different parts of it

I need to update the url stored in a column.
My columns have values like this:
https://www.site.sharepoint.com/sites/test/AB-19-CALL
I want to update this URL to:
https://www.site.sharepoint.com/sites/test/CALL-AB-19
To get the last part which is AB-19-CALL, I used the below query
SELECT
SUBSTRING(urlcompte, LEN(urlcompte) - CHARINDEX('/', REVERSE(urlcompte)) + 2, LEN(urlcompte)),
UrlCompte
FROM
tblAccount
Now to split and reverse the AB-19-call I would again need to use the entire query above and then select substring using -
Is there an easier way to do this?
In C# we can do something like this:
urlCompte.Split('-')[2] + urlCompte.Split('-')[0] + urlCompte.Split('-')[1]
Is there a way in SQL Server to split the column and access different parts of it?
This would work to split the string parts -
DECLARE #txt NVARCHAR(500)= 'https://www.site.sharepoint.com/sites/test/AB-19-CALL';
SELECT value
FROM STRING_SPLIT(REVERSE(SUBSTRING(REVERSE(#txt), 1, CHARINDEX('/', REVERSE(#txt))-1)), '-');(substring(reverse(#txt),1,charindex('/',reverse(#txt))-1)),'-')
If you are so lucky to be using SQL Server 2017 you can use for string_agg function for concatenating splitted string pieced with SQL string_split function
Here is the script to change the order of last part in your url
declare #url varchar(100) = 'CALL-AB-19'
select
string_agg(value,'-') within group (order by rn desc)
from (
select
value, row_number() over (order by #url) as rn
from STRING_SPLIT( #url , '-' )
) t
If you want to apply this solution as a set based solution on your table rows with a single SELECT statement, you can execute following SQL
select
id, string_agg(value,'-') within group (order by rn desc)
from (
select
id, value, row_number() over (partition by id order by url) as rn
from urlList
cross apply STRING_SPLIT( url , '-' )
) t
group by id
I assume, in your table urlList, you have a PK field id
If you don't use SQL Server 2016 for split function and SQL Server 2017 for string aggregate function, you can search the web for split string function samples. And using FOR XML Path to concatenate string parts, you can build a solution with the help of CTE expression as follows
;with cte as (
select
urlList.id,
urlList.url,
s.id sid,
s.val
from urlList
cross apply dbo.split(url,'-' ) s
)
SELECT
distinct
id,
STUFF(
(
SELECT
'-' + u.val
FROM cte as u
where u.id = cte.id
Order By sid desc
FOR XML PATH('')
), 1, 1, ''
) As newurl
FROM cte
Please note that the referred split function returns an id named numeric field which shows the order of the splitted piece. So while concatenating I use an "order by" clause on the same field this time in descending order
If someone is using SQL server 2012 or older version then it can be possible by this way:
DECLARE #URL VARCHAR(100) = 'https://www.site.sharepoint.com/sites/test/AB-19-CALL'
SELECT TOP 1 dbo.[Reversedata](DATA, '-')
FROM (SELECT * FROM dbo.Splitter(#URL, '/') as t) as tt order by Id desc
In above code I have used two functions:
1) Splitter : To split the string (https://ole.michelsen.dk/blog/split-string-to-table-using-transact-sql.html)
2) Reversedata: To reverse the data (http://picnicerror.net/development/sql-server/reverse-order-words-string-sql-server-2012-01-16/)
Splitter:
CREATE FUNCTION [dbo].[Splitter]
(
#String NVARCHAR(4000),
#Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
WITH Split(stpos,endpos)
AS(
SELECT 0 AS stpos, CHARINDEX(#Delimiter,#String) AS endpos
UNION ALL
SELECT endpos+1, CHARINDEX(#Delimiter,#String,endpos+1)
FROM Split
WHERE endpos > 0
)
SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
'Data' = SUBSTRING(#String,stpos,COALESCE(NULLIF(endpos,0),LEN(#String)+1)-stpos)
FROM Split
)
GO
Reverse:
CREATE FUNCTION [dbo].[udf_ReverseSequenceOrder] (
#Input nvarchar(200)
,#Delimiter nvarchar(5)
)
RETURNS nvarchar(200)
AS
BEGIN
DECLARE #Output nvarchar(200)
WHILE LEN(#Input) > 0
BEGIN
IF CHARINDEX(#Delimiter, #Input) > 0
BEGIN
SET #Output = SUBSTRING(#Input,0,CHARINDEX(#Delimiter, #Input)) + #Delimiter + ISNULL(#Output,'')
SET #Input = SUBSTRING(#Input,CHARINDEX(#Delimiter, #Input)+1,LEN(#Input))
END
ELSE
BEGIN
SET #Output = #Input + #Delimiter + ISNULL(#Output,'')
SET #Input = ''
END
END
RETURN SUBSTRING(#Output,0,LEN(#Output))
END
Well, this is the xml based solution. For SQL Server 2008 and above.
DECLARE #url VARCHAR(100) = 'AB-19-CALL'
SELECT MyUrl FROM
(
SELECT CAST('<Url><Part>' + REPLACE(#url,'-','</Part><Part>') + '</Part></Url>' AS XML) AS my_Xml
) t1
CROSS APPLY
(
SELECT
my_Data.D.value('Part[3]','varchar(50)') + '-' +
my_Data.D.value('Part[1]','varchar(50)') + '-' +
my_Data.D.value('Part[2]','varchar(50)') AS MyUrl
FROM t1.my_Xml.nodes('/Url') as my_Data(D)
) t2
Result
MyUrl
----------
CALL-AB-19

Get the value of a column replacing the comma separator

How can I get each value of a column that has a comma separator in her value ?
Example:
ID ColumnUnified
1 12,34,56,78
2 80,99,70,56
What I want is a query to get the number without comma. If possible, in collumns.
12 34 56 78
This will work for any number of values http://beyondrelational.com/modules/2/blogs/70/posts/10844/splitting-delimited-data-to-columns-set-based-approach.aspx
The solution Madhivanan's link refers to is very creative, but I had a slight problem with it on SQL Server 2012 related to the name of one of the columns (Start). I've modified the code in his answer to use StartPos instead of Start for the column name.
I was not familiar with the system procedure spt_values, but I found a very informative description of the procedure here on SO for those who are interested in exactly how this solution works.
Finally, here's the (slightly) revised code from Madhivana's answer:
CREATE TABLE #test(id int, data varchar(100))
INSERT INTO #test VALUES (1,'This,is,a,test,string')
INSERT INTO #test VALUES (2,'See,if,it,can,be,split,into,many,columns')
DECLARE #pivot varchar(8000)
DECLARE #select varchar(8000)
SELECT #pivot = COALESCE(#pivot + ',', '') + '[col'
+ CAST(number + 1 AS VARCHAR(10)) + ']'
FROM master..spt_values
WHERE type = 'p'
AND number <= ( SELECT MAX(LEN(data) - LEN(REPLACE(data, ',', '')))
FROM #test
)
SELECT #select = '
select p.*
from (
select
id,substring(data, StartPos+2, endPos-StartPos-2) as token,
''col''+cast(row_number() over(partition by id order by StartPos) as varchar(10)) as n
from (
select
id, data, n as StartPos, charindex('','',data,n+2) endPos
from (select number as n from master..spt_values where type=''p'') num
cross join
(
select
id, '','' + data +'','' as data
from
#test
) m
where n < len(data)-1
and substring(data,n+1,1) = '','') as data
) pvt
Pivot ( max(token)for n in (' + #pivot + '))p'
EXEC(#select)
DROP TABLE #test