3

I have the following string to split into two columns:

Given:

DECLARE @String VARCHAR(MAX) = 'Mak^1,Jak^2,Smith^3,Lee^4,Joseph^5'

I want to split it into two columns:

column1  column2
-----------------
Mak      1
Jak      2
Smith    3
Lee      4
Joseph   5

My try:

Table-valued Function:

CREATE FUNCTION [dbo].[udf_Split]
(
@InputString VARCHAR(8000), 
@Delimiter VARCHAR(50)
)
RETURNS @Items TABLE (ID INTEGER IDENTITY(1,1), Item VARCHAR(8000))

AS
BEGIN
      IF @Delimiter = ' '
      BEGIN
            SET @Delimiter = ','
            SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
      END
      IF (@Delimiter IS NULL OR @Delimiter = '')
            SET @Delimiter = ','

      DECLARE @Item VARCHAR(8000)
      DECLARE @ItemList VARCHAR(8000)
      DECLARE @DelimIndex INT

      SET @ItemList = @InputString
      SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      WHILE (@DelimIndex != 0)
      BEGIN
            SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
            INSERT INTO @Items VALUES (@Item)

            SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
            SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      END -- End WHILE

      IF @Item IS NOT NULL 
      BEGIN
            SET @Item = @ItemList
            INSERT INTO @Items VALUES (@Item)
      END

      ELSE INSERT INTO @Items VALUES (@InputString)

      RETURN

END 

Function calling:

SELECT Item FROM [dbo].[udf_Split](@String ,',');

Output:

Item
--------------
Mak^1
Jak^2
Smith^3
Lee^4
Joseph^5
1
  • 2
    Probably SELECT LEFT(Item, CHARINDEX('^', Item) - 1) AS Column1, RIGHT(Item, LEN(Item) - CHARINDEX('^', Item)) AS Column2 FROM [dbo].[udf_Split](@String ,',') will be enough. Commented Sep 18, 2019 at 10:38

5 Answers 5

4

First, Please note that SQL Server 2008 r2 is out of extended support. It's high time to upgrade to a newer version.

For a single string, I would probably use a little dynamic SQL magic trick:

DECLARE @String VARCHAR(MAX) = 'Mak^1,Jak^2,Smith^3,Lee^4,Joseph^5'

DECLARE @Sql VARCHAR(MAX) = 'SELECT Name,Id FROM (VALUES (''' + REPLACE(REPLACE(REPLACE(@String,'''',''''''), ',', '),('''), '^', ''',') + ')) V(Name, Id)';

-- @Sql now contains this:
-- SELECT Name,Id FROM (VALUES ('Mak',1),('Jak',2),('Smith',3),('Lee',4),('Joseph',5)) V(Name, Id)

EXEC(@Sql)

Results:

Name    Id
Mak     1
Jak     2
Smith   3
Lee     4
Joseph  5
Sign up to request clarification or add additional context in comments.

2 Comments

That's actually a really interesting, and different, way to approach this.
I recommend using REPLACE(@String,'''','''''') though; as otherwise this is open to injection (as we don't know where the value of @String is coming from).
4

In the most recent versions of SQL Server, you can use string_split():

select left(s.value, charindex('^', value) - 1) as column1,
       stuff(s.value, 1, charindex('^', value), '') as column2
from string_split(@string, ',') s ;

You might find it most convenient to download a split function to handle this.

Otherwise, I think a recursive CTE is a simple enough approach:

with cte as (
      select convert(varchar(max), null) as row,
             @string as str
      union all
      select convert(varchar(max), left(str, charindex(',', str + ',') - 1)),
             convert(varchar(max), stuff(str, 1, charindex(',', str + ','), ''))
      from cte
      where str <> '' 
     )
select left(cte.row, charindex('^', cte.row) - 1) as column1,
       stuff(cte.row, 1, charindex('^', cte.row), '')
from cte
where row is not null;

Here is a db<>fiddle.

Comments

1

I feel a much better approach to this would be to get rid of that awful WHILE and use a set based approach; we'll be using delimitedsplit8K here (if you are on 2012+ use delimitedsplit8k_lead or on 2016+ you can STRING_SPLIT).

With that in mind, the above becomes quite trivial:

DECLARE @String varchar(MAX) = 'Mak^1,Jak^2,Smith^3,Lee^4,Joseph^5';

SELECT LEFT(DS.Item,CHARINDEX('^',DS.Item)-1) AS Col1,
       STUFF(DS.Item,1, CHARINDEX('^',DS.Item),'') AS Col2
FROM dbo.DelimitedSplit8K(@String, ',') DS;

Comments

1

Try This Script below

DECLARE @String VARCHAR(MAX) = 'Mak^1,Jak^2,Smith^3,Lee^4,Joseph^5';

DECLARE @TempTable AS TABLE(data VARCHAR(MAX))
INSERT INTO @TempTable
SELECT @String

;WITH CTE
AS
(
SELECT Split.A.value('.','nvarchar(1000)') AS data
FROM 
(
SELECT CAST('<S>'+REPLACE(data,',','</S><S>')+'</S>' AS XML ) AS data
FROM @TempTable
)AS A
CROSS APPLY data.nodes('S') AS Split(A)
)
SELECT LTRIM(RTRIM(SUBSTRING(data,0,CHARINDEX('^',data)))) AS column1,
       LTRIM(RTRIM(SUBSTRING(data,CHARINDEX('^',data)+1,LEN (data)))) AS column2
FROM CTE

Result

column1 column2
-------------------
Mak         1
Jak         2
Smith       3
Lee         4
Joseph      5

Use the above script create table valued parameter function

CREATE FUNCTION [dbo].[udf_SplitFun](@InputData VARCHAR(MAX))
RETURNS @Return TABLE ( column1 VARCHAR(200),column2 INT)
AS
BEGIN
DECLARE @TempTable AS TABLE
(
data VARCHAR(MAX)
)
INSERT INTO @TempTable
SELECT @InputData

;WITH CTE
AS
(
SELECT Split.A.value('.','nvarchar(1000)') AS data
FROM 
(
SELECT CAST('<S>'+REPLACE(data,',','</S><S>')+'</S>' AS XML ) AS data
FROM @TempTable
)AS A
CROSS APPLY data.nodes('S') AS Split(A)
)
INSERT INTO @Return(column1,column2)
SELECT LTRIM(RTRIM(SUBSTRING(data,0,CHARINDEX('^',data)))) AS column1,
       LTRIM(RTRIM(SUBSTRING(data,CHARINDEX('^',data)+1,LEN (data)))) AS column2
FROM CTE

RETURN;

END

Execute the Function like below

DECLARE @InputData VARCHAR(MAX) = 'Mak^1,Jak^2,Smith^3,Lee^4,Joseph^5';

SELECT * FROM [dbo].[udf_SplitFun] (@InputData)
GO

Comments

1

You may use that split function another time to split each line by caret. Like:

SELECT SplitByCaret1.Item, SplitByCaret2.Item 
FROM [dbo].[udf_Split](@String ,',') SplitByComma
CROSS APPLY (SELECT * FROM [dbo].[udf_Split](SplitByComma.Item ,'^') Splitted WHERE Splitted.ID=1) SplitByCaret1
CROSS APPLY (SELECT * FROM [dbo].[udf_Split](SplitByComma.Item ,'^') Splitted WHERE Splitted.ID=2) SplitByCaret2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.