Delimited String Parsing in SQL Server 2005 and later

AID: 192
  • Status: Published

6916 points

Awards
  • Community Pick
This article will describe one method to parse a delimited string into a table of data.  

Why would I do that you ask?  Let's say that you need to pass multiple parameters into a stored procedure to search for.  For our sake, we'll say that we want to return a list of items with their details, given a list of item numbers.


1

Create the view the function depends on

Execute the following code to create the vw_Nums view.  You will need to run it in SQL Server Management Studio's Query tool, not in the query builder.  I use a view to generate a list of 4 billion numbers.   But if your database has a numbers table, you can use it as well.  Just update vw_Nums in the function with your table name and "n" (without quotes) with your column name.  Just be sure that you have enough numbers.  There has to be at least as many numbers as characters in your input string.  The view's code is also in a comment in the function so that if it gets dropped, it can be recreated by copying the text out of the function.


create view vw_Nums
as
with   cte0 as (select 1 as c union all select 1), 
       cte1 as (select 1 as c from cte0 a, cte0 b), 
       cte2 as (select 1 as c from cte1 a, cte1 b), 
       cte3 as (select 1 as c from cte2 a, cte2 b), 
       cte4 as (select 1 as c from cte3 a, cte3 b), 
       cte5 as (select 1 as c from cte4 a, cte4 b), 
       nums as (select row_number() over (order by c) as n from cte5)
       select n from nums 
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

Select allOpen in new window


2

Create the function

The below code snippet will create the function.


if object_id('[dbo].[fn_DelimitedToTable]') is not null
     drop function [dbo].[fn_DelimitedToTable]
go
create function [dbo].[fn_DelimitedToTable](@DelimitedString nvarchar(max), @Delimiter nvarchar(32))
returns @Values TABLE
     (ident         int not null identity primary key clustered
     ,thePosition   int not null
     ,theValue      nvarchar(max)
     )
as
/************************************************************
*
*    Author:        Brandon Galderisi
*    Last modified: 07-Oct-2008
*    Purpose:       splits an input string (@DelimitedString) 
*                   on a delimiter (@delimiter) and outputs 
*                   a table of values.
*    
*
*************************************************************/
begin

insert into @Values (thePosition,theValue)
		select n, substring(@delimiter + @DelimitedString + @delimiter, n + (datalength(@delimiter)/2), charindex(@delimiter, @delimiter + @DelimitedString + @delimiter, n + datalength(@delimiter)/2) - n - datalength(@delimiter)/2) as string_value
		from	dbo.vw_Nums
		where
			n <= (datalength(@delimiter + @DelimitedString + @delimiter)/2) - (datalength(@delimiter)/2)
			and substring(@delimiter + @DelimitedString + @delimiter, n, (datalength(@delimiter)/2)) = @delimiter



return
end
/*
-- The purpose of vw_Nums is if the source database does not have a numbers table.  This view (vw_nums)
-- will allow the parsing of up to 4 billion+ character strings with the above function.  Whether a static
-- table or this view is used for fn_DelimitedToTable, it can only split a string as long as the source 
-- numbers table.
Requires a nunbers table or this view:
create view vw_Nums
as
with   cte0 as (select 1 as c union all select 1), 
       cte1 as (select 1 as c from cte0 a, cte0 b), 
       cte2 as (select 1 as c from cte1 a, cte1 b), 
       cte3 as (select 1 as c from cte2 a, cte2 b), 
       cte4 as (select 1 as c from cte3 a, cte3 b), 
       cte5 as (select 1 as c from cte4 a, cte4 b), 
       nums as (select row_number() over (order by c) as n from cte5)
       select n from nums 



Sample Usage:
select * from [dbo].[fn_DelimitedToTable]('a|%25basdf|%25c|%25d','|%25')
select theValue from [dbo].[fn_DelimitedToTable]('a','|')
select * from [dbo].[fn_DelimitedToTable]('a basdf c d',' ')
*/
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:

Select allOpen in new window


3

Enjoy

The code is ready



You are now ready to use it.  Above in the comment you will see that I have 3 sample calls.

select * from [dbo].[fn_DelimitedToTable]('a|%25basdf|%25c|%25d','|%25')
select theValue from [dbo].[fn_DelimitedToTable]('a','|')
select * from [dbo].[fn_DelimitedToTable]('a basdf c d',' ')

The first shows using a multi character delimiter.  This is useful because single character delimiters mean that that character is not valid inside of the string you are parsing.  Depending on your needs, that may be OK.  For example, a comma (,) is often a good delimiter.  The output of the query is 3 columns.  

Ident - An identity field representing the "chunk" of the string.
thePosition - The starting position of the string.
theValue - The value!

The first query returns the following:
1      1      a
2      6      basdf
3      15      c
4      20      d

Second:
a

Third:
1      1      a
2      3      basdf
3      9      c
4      11      d

This shows that many different delimiters, including a space, can be used to output data.


Now back to the item list example.  Let's say that you have a table called items.  This code sample will setup an items table, populate it with data, and show you how to select data from is using the function with a stored procedure.

create table #items
     (item_id       int not null identity primary key clustered
     ,item_name     nvarchar(32)
     )
go
insert into #items(item_name) values('Hammer')
insert into #items(item_name) values('Saw')
insert into #items(item_name) values('Drill')
GO
create procedure up_GetMyItems @ItemList nvarchar(1000), @Delimiter nvarchar(100)
as

select * from #items i
 join (select cast(theValue as int) item_id from dbo.fn_DelimitedToTable(@ItemList,@Delimiter)) iFilter
  on i.item_id = iFilter.item_id

go

exec up_GetMyItems @itemlist = '1,2', @Delimiter=','
exec up_GetMyItems @itemlist = '2,3', @Delimiter=','
exec up_GetMyItems @itemlist = '1,3', @Delimiter=','
go
drop procedure up_GetMyItems 
drop table #items
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:

Select allOpen in new window



This topic is also covered on my site SQL Server Nation under the title Converting a delimited string into a table.  Stop over there and check out the site!
Asked On
2008-11-20 at 16:53:24ID192
Tags

parse

,

string parsing

,

delimited string

,

user defined function

,

sql server 2005

,

sql server 2008

Topic

SQL Server 2005

Views
6590

Comments

Expert Comment

by: mwvisa1 on 2008-11-24 at 04:47:36ID: 411

Nice, Brandon.  The common table expression to generate the numbers view always impresses me.

Author Comment

by: BrandonGalderisi on 2008-11-24 at 14:54:40ID: 415

I'll mention again that I'm not the author of that CTE!

Expert Comment

by: mwvisa1 on 2008-11-25 at 05:12:10ID: 419

Who wrote that then, Tim?

Author Comment

by: BrandonGalderisi on 2008-11-25 at 07:21:52ID: 422

This was posted over at SQL Server Central where I posted use of the same CTE (referencing there that I was not the original author of the CTE as well).


Just an FYI... the source of the CTE in your article is by a fellow called Itzik Ben-Gan and can be found at the bottom of page 255 in a book titled "Inside Microsoft SQL Server 2005 - T-SQL Querying".

--Jeff Moden

Expert Comment

by: meeran03 on 2010-08-22 at 20:32:11ID: 18638

nice presentation . i enjoyed reading it .
Short and sweet


Meeran03

Add your Comment

Please Sign up or Log in to comment on this article.

Join Experts Exchange Today

Gain Access to all our Tech Resources

Get personalized answers

Ask unlimited questions

Access Proven Solutions

Search 3.2 million solutions

Read In-Depth How-To Guides

1000+ articles, demos, & tips

Watch Step by Step Tutorials

Learn direct from top tech pros

And Much More!

Your complete tech resource

See Plans and Pricing

30-day free trial. Register in 60 seconds.

Loading Advertisement...

Top MS SQL Server 2005 Experts

  1. ScottPletcher

    195,617

    Guru

    8,500 points yesterday

    Profile
    Rank: Genius
  2. jogos

    176,191

    Guru

    668 points yesterday

    Profile
    Rank: Sage
  3. acperkins

    140,953

    Master

    1,000 points yesterday

    Profile
    Rank: Genius
  4. TempDBA

    113,707

    Master

    1,168 points yesterday

    Profile
    Rank: Sage
  5. matthewspatrick

    93,824

    Master

    1,600 points yesterday

    Profile
    Rank: Savant
  6. lcohan

    93,302

    Master

    2,000 points yesterday

    Profile
    Rank: Genius
  7. dtodd

    84,612

    Master

    0 points yesterday

    Profile
    Rank: Genius
  8. mwvisa1

    76,166

    Master

    0 points yesterday

    Profile
    Rank: Genius
  9. ValentinoV

    76,011

    Master

    1,800 points yesterday

    Profile
    Rank: Genius
  10. ralmada

    55,844

    Master

    400 points yesterday

    Profile
    Rank: Genius
  11. anujnb

    54,164

    Master

    0 points yesterday

    Profile
    Rank: Wizard
  12. angelIII

    53,846

    Master

    10 points yesterday

    Profile
    Rank: Elite
  13. EugeneZ

    53,602

    Master

    0 points yesterday

    Profile
    Rank: Genius
  14. HainKurt

    49,150

    0 points yesterday

    Profile
    Rank: Genius
  15. Buttercup1

    48,568

    0 points yesterday

    Profile
    Rank: Master
  16. huslayer

    40,600

    0 points yesterday

    Profile
    Rank: Sage
  17. appari

    39,400

    0 points yesterday

    Profile
    Rank: Genius
  18. tim_cs

    34,200

    0 points yesterday

    Profile
    Rank: Wizard
  19. wdosanjos

    33,836

    0 points yesterday

    Profile
    Rank: Genius
  20. dqmq

    31,136

    0 points yesterday

    Profile
    Rank: Genius
  21. Cluskitt

    30,940

    0 points yesterday

    Profile
    Rank: Wizard
  22. SJCFL-Admin

    30,877

    0 points yesterday

    Profile
    Rank: Master
  23. jimhorn

    29,975

    0 points yesterday

    Profile
    Rank: Genius
  24. Brichsoft

    28,107

    0 points yesterday

    Profile
    Rank: Sage
  25. momi_sabag

    27,903

    0 points yesterday

    Profile
    Rank: Genius

Hall Of Fame