SQL Server Nation
For all of your SQL Server needs.
Converting a delimited string into a table

In this article, I will show you how you can convert a delimited string of data into a table of data.  In order to do this we will use a table valued function.  There are many ways to achieve this but this how I like to do it. 

In order to use the function, you will need a numbers table.  Since that's a topic that we haven't covered here yet, we will utilize a view that builds one on the fly.  The view can be found in the A View of Numbers post.  If you have a numbers table, replace "vw_nums" with the name of the table in the below function and replace "n" with the column name that contains your numbers.

Run the following SQL to create the function.

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
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

GO

 

This function works by utilizing the numbers table to represent the characters in the string.  This allows SQL Server to quickly find the @Delimiter in the string without doing any sort of while loops or cursors.  It accepts a @DelimitedString and a @delimiter as input, and outputs three values.  The @DelimitedString input parameter is a nvarchar(max) input parameter, but the actual string to be parsed can be no longer than the number of values in your numbers table.The "ident" field is an identity field that represents the position of the parsed string within the @DelimitedString.  The field "thePosition" represents the starting position of the value within the @DelimitedString.  The field "theValue" is the value within the @DelimitedString that falls between two instances of the @Delimiter.

 

Sample usage:
This will show you the basics of how this function works and what you can expect to see.

select * from [dbo].[fn_DelimitedToTable]('Jim,John,Mike,Bob,Tom',',')

 

As you can see, it returns the five names in the string, in the order they appeared.  This script is useful when an application has to pass in a delimited list of values to search for.  By splitting the values into a table it can be joined to for selecting multiple values.

This example shows that you can use a delimiter greater than one character.  This is useful when your data can contain any character and there is no ONE character that you can use to delimit the string.

 

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

 


 

Now let's talk about some possible uses for this type of functionality. 

Let's say that your application needs to search and return a list of employees.  There are many ways to pass in the parameters.  One of which is XML.  But SQL Server isn't the most efficient as processing XML so for this case we will use a delimited string.  The first thing we need to do is setup our test table

Note: If the table name looks strange, I use a partial newid() value to make the table unique.  Although we recommend that you never test on a production server, or even in a used database on a development server, we try to make the names unique to prevent conflicting with your existing tables.

 

create table dbo.employees_FB8AD58DADAF
(userid int identity primary key clustered
,firstname nvarchar(50) not null
,lastname nvarchar(50) not null
)
GO
insert into dbo.employees_FB8AD58DADAF(firstname,lastname)
select 'Jim', 'Smith'
union all select 'John', 'Smith'
union all select 'Mike', 'Smith'
union all select 'Bob', 'Smith'
union all select 'Tom', 'Smith'
union all select 'Tim', 'Smith'
union all select 'Rob', 'Smith'
union all select 'Matt', 'Smith'

 

 

Now let's see how we can use the above function to search.  The below procedure accepts a @userlist parameter.  The @userlist parameter is a comma delimited list of user first names to search for in the table we created.  When we create and run the below procedure

 

create procedure dbo.up_employeesearch
@UserList nvarchar(max)
as
set nocount on
select e.userid,e.firstname,e.lastname from dbo.employees_FB8AD58DADAF e
join [dbo].[fn_DelimitedToTable](@userlist,N',') t
on e.firstname = t.thevalue
go
exec dbo.up_employeesearch @userlist = 'Jim,John,Mike,Bob,Tom'

 

We get the following results:

 

 

There are a lot of uses for this type of functionality and I'm sure you can already think of a few.  Just remember that before you start making too much use of this, you should consider converting it to use a numbers table instead of the vw_nums view.

 


Posted 7 Mar 2009 12:25 AM by BrandonGalderisi
Copyright SQL Server Nation 2009
Powered by Community Server (Non-Commercial Edition), by Telligent Systems