Home Contact

Brian Sherwin's Blog

Moving at the Speed of .Net

News

Twitter












Tag Cloud


Archives

Links

Syndication:

Using a Table Valued Function in a JOIN

During my presentation on "Avoiding Database Entropy" I did a demo of a function to parse a delimited string and return it as a table.  This is extremely helpful when using multi-select controls in your applications.  In the end we still call the stored procedure like this:

GetUsersByID '1,2,7,9'

Most people make their stored procedure like this:

create proc GetUsersByID (@delimitedIDs varchar(200))
as
declare @SQL varchar(2000)
set @SQL = 'SELECT  Employee.EmployeeID, Employee.FirstName, Employee.LastName,
        Employee.MiddleName
FROM    Employee
WHERE EmployeeID in (' + @delimitedIDs + ')'
sp_executesql (@SQL)

Notice all that "RED SQL" -- left over from the Cold War I'm sure.

With a little creativity, we can improve performance, maintenance and clarity by doing it like this:

create proc GetUsersByID (@delimitedIDs varchar(200))
as
SELECT  Employee.EmployeeID, Employee.FirstName, Employee.LastName,
        Employee.MiddleName
FROM    Employee 
INNER JOIN dbo.ParamParserFn(@delimitedIDs, ',') tblID
ON Employee.EmployeeID = tblID.Id

Notice the subtle difference?  There's no dynamic SQL.  It's all good!  It will perform better too.

So here is the parsing function (note: be sure you qualify it correctly when you go to use it--SQL will like you better...wink, wink):

CREATE FUNCTION ParamParserFn( @delimString varchar(255), @delim char(1)) 
RETURNS @paramtable 
TABLE ( Id int ) 
AS BEGIN

DECLARE @len int,
        @index int,
        @nextindex int

SET @len = DATALENGTH(@delimString)
SET @index = 0
SET @nextindex = 0


WHILE (@len > @index )
BEGIN

SET @nextindex = CHARINDEX(@delim, @delimString, @index)

if (@nextindex = 0 ) SET @nextindex = @len + 2

 INSERT @paramtable
 SELECT SUBSTRING( @delimString, @index, @nextindex - @index )


SET @index = @nextindex + 1

END
 RETURN
END
GO

Your mileage may vary as you may need strings delimited and not just integers, but this should get you going down the right path.  I don't claim this as my own code, but I've been using this method for so many years, I can't remember where I first learned the idea.


Feedback

# re: Using a Table Valued Function in a JOIN

Works great thank you! Just a minor change though to make it work perfectly though.

As is it will drop the last int if you do not have a trailing comma ie '14,15' will return 14 rather than 14 & 15.

Easily fixed just
Change the following
WHILE (@len > @index) to using a >= sign.

Note, leading commas are not handled and as such add a zero to the list.


Thanks again! 1/22/2008 10:52 AM | Bradley

# re: Using a Table Valued Function in a JOIN

Here's another version without the while loops.

(Although while loops are not as bad as cursors, I would advise against using them as set-based operations are almost always faster.)

http://www.sqlteam.com/article/parsing-csv-values-into-multiple-rows 4/6/2009 2:59 PM | An Phu

# re: Using a Table Valued Function in a JOIN

Thanks for this help ... 8/5/2009 4:45 AM | Girish kalwadia

# re: Using a Table Valued Function in a JOIN

yeah avoid cursors as much as humanly possible! 8/28/2009 4:11 AM | pico projectors

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: