9

I have a varchar @a='a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p', which has | delimited values. I want to split this variable in a array or a table.

How can I do this?

2

4 Answers 4

13

Use a table valued function like this,

CREATE FUNCTION Splitfn(@String varchar(8000), @Delimiter char(1))       
returns @temptable TABLE (items varchar(8000))       
as       
begin       
    declare @idx int       
    declare @slice varchar(8000)       

    select @idx = 1       
        if len(@String)<1 or @String is null  return       

    while @idx!= 0       
    begin       
        set @idx = charindex(@Delimiter,@String)       
        if @idx!=0       
            set @slice = left(@String,@idx - 1)       
        else       
            set @slice = @String       

        if(len(@slice)>0)  
            insert into @temptable(Items) values(@slice)       

        set @String = right(@String,len(@String) - @idx)       
        if len(@String) = 0 break       
    end   
return      

end

and get your variable and use this function like this,

SELECT i.items FROM dbo.Splitfn(@a,'|') AS i
Sign up to request clarification or add additional context in comments.

4 Comments

@gbn does table of numbers execute faster than a loop.... Please explain a bit more...
Please see my links in my answer
There are more elegant solutions out there but when supporting legacy code bases from SQL 2005 and below this is the only choice
should you cleanup the temp table that is returned from the function?
2

In general, this is such a common question here

I'll give the common answer: Arrays and Lists in SQL Server 2005 and Beyond by Erland Sommarskog

I'd recommend a table of numbers, not a loop, for general use.

1 Comment

Perhaps you could improve the answer by explaining how to apply this method to split a text at each delimiter. =)
2

Try this one:

declare @a varchar(10) 
set @a = 'a|b|c|'
while len(@a) > 1
begin
insert into #temp
select substring(@a,1,patindex('%|%',@a)-1);
set @a = substring(@a,patindex('%|%',@a)+1,len(@a))
end;

2 Comments

Nice solution, but need to clarify - it's important that string should be ended with delimiter symbol. If it won't - you will fall into infinite cycle
my extension to your solution is to add this clause after your "set @a" row: IF(patindex('%|%',@a)=0) BEGIN INSERT INTO #temp select @a; BREAK; END;
1

Here's an alternative XML based solution. It seems to have a similar performance as the Splitfn() solution.

This converts varchar a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p into XML <a>a</a><a>b</a><a>c</a><a>d</a><a>e</a><a>f</a><a>g</a><a>h</a><a>i</a><a>j</a><a>k</a><a>l</a><a>m</a><a>n</a><a>o</a><a>p</a> and extracts the value from each XML <a> node.

declare @a      varchar(max);
set @a  =   'a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p';

declare @xml    xml;
set @xml    
    =   '<a>'+replace(replace(replace(@a,'&','&amp;'),'<','&lt;'),'|','</a><a>')+'</a>';

SELECT  x.n.value('.','VARCHAR(1)') AS  singleValue
FROM    @xml.nodes('/a') AS  x(n)
;

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.