Technology Musings
A very common task for database developers taking reigns of an existing project is to normalize data. I needed a convenient way to split delimited values into a table for transformation purposes. After finding a wonderful algorithm, I decided to enhance it and transform it to a User-Defined Function in the process. Be aware that the function depends on a Tally table to exist – much like you might have with a Calendar table to join against.
To start, instantiate dbo.Tally:
1 2 3 4 5 6 7 8 | CREATE TABLE dbo.Tally (ID INT PRIMARY KEY) DECLARE @a INT SET @a = 1 WHILE (@a <= 8000) BEGIN INSERT INTO dbo.Tally VALUES(@a) SET @a = @a + 1 END |
Define the actual UDF:
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 | CREATE FUNCTION dbo.f_ListToTable ( @Items VARCHAR(MAX) , @Delimiter VARCHAR(5) = ',' ) RETURNS @OutputItems TABLE (Item VARCHAR(MAX)) AS BEGIN --Original idea from http://sqlblog.com/blogs/peter_debetta/archive/2004/02/16/33.aspx --Accessed 2008-09-22 DECLARE @InputItems TABLE (Item VARCHAR(MAX)) INSERT INTO @InputItems VALUES (@Items) INSERT INTO @OutputItems SELECT NULLIF(SUBSTRING(@Delimiter + Item + @Delimiter , ID, CHARINDEX(@Delimiter , @Delimiter + Item + @Delimiter , ID) - ID) , '') FROM dbo.Tally INNER JOIN @InputItems ON ID <= LEN(@Delimiter + Item + @Delimiter) AND SUBSTRING(@Delimiter + Item + @Delimiter , ID - LEN(@Delimiter), LEN(@Delimiter)) = @Delimiter AND CHARINDEX(@Delimiter , @Delimiter + Item + @Delimiter , ID) - ID > 0 RETURN END |
And some test cases:
SELECT * FROM dbo.f_ListToTable('A,rose,by,any,other,name,smells,just,as,sweet', DEFAULT) SELECT * FROM dbo.f_ListToTable('Bill Gates;|Jackie Robinson;|Lisa Simpson;|Jeff Bridges;|', ';|')
And the results:
Item -------------------- A rose by any other name smells just as sweet (10 row(s) affected) Item -------------------- Bill Gates Jackie Robinson Lisa Simpson Jeff Bridges (4 row(s) affected)
Notes: