THE SQL Server Blog Spot on the Web
Welcome to SQLblog.com - The SQL Server blog spot on the web Sign in | Join | Help
in Search

Adam Machanic

Adam Machanic, Boston-based independent database consultant, writer, and speaker, shares his experiences with programming, performance tuning, and optimizing SQL Server 2000, 2005, and 2008, in conjunction with related technologies such as .NET.

Splitting a string of unlimited length

Originally posted here.

There are many techniques for splitting a string in T-SQL (in other words, taking a character-delimited string and producing a table of the values), the best of which are encapsulated in Erland Sommarskog's famous article. My favorite of his string splitting techniques is adapted from a previous example that was created by Anith Sen.

Both of these resources are excellent, but sometimes you just need a little bit more. None of their solutions will split a string larger than 8000 characters in length. So I've produced my own modified version. If you're splitting smaller strings then by all means, use theirs! This is certainly slower, but I do believe it's the fastest way in SQL Server 2000 to split a very long string. You will require a numbers table, so make sure you have it on hand...

Anyway, the code:

 

CREATE FUNCTION dbo.SplitString
(
@List TEXT,
@Delimiter CHAR(1)
)
RETURNS @ReturnTbl TABLE (OutParam VARCHAR(20))
WITH SCHEMABINDING
AS
BEGIN
DECLARE @LeftSplit VARCHAR(7998)
DECLARE @SplitStart INT SET @SplitStart = 0
DECLARE @SplitEnd INT
SET @SplitEnd = 7997

SELECT @SplitEnd = MAX(Number)
FROM dbo.Numbers
WHERE (SUBSTRING(@List, Number, 1) = @Delimiter
OR Number = DATALENGTH(@List) + 1)
AND Number BETWEEN @SplitStart AND @SplitEnd

WHILE @SplitStart < @SplitEnd
BEGIN
SET @LeftSplit = @Delimiter + SUBSTRING(@List, @SplitStart, @SplitEnd - @SplitStart) + @Delimiter

INSERT @ReturnTbl (OutParam)
SELECT LTRIM(RTRIM(SUBSTRING(@LeftSplit, Number + 1,
CHARINDEX(@Delimiter, @LeftSplit, Number + 1) - Number - 1)))
AS Value
FROM dbo.Numbers
WHERE Number <= LEN(@LeftSplit) - 1
AND SUBSTRING(@LeftSplit, Number, 1) = @Delimiter
AND SUBSTRING(@LeftSplit, Number + 1,
CHARINDEX(@Delimiter, @LeftSplit, Number + 1) - Number - 1) <> ''

SET @SplitStart = @SplitEnd + 1
SET @SplitEnd = @SplitEnd + 7997

SELECT @SplitEnd = MAX(Number) + @SplitStart
FROM dbo.Numbers
WHERE (SUBSTRING(@List, Number + @SplitStart, 1) = @Delimiter
OR Number+@SplitStart = DATALENGTH(@List) + 1)
AND Number BETWEEN 1 AND @SplitEnd - @SplitStart
END

RETURN
END

This code does nothing more than chunk up the string, using the delimiter as boundries, into small enough pieces (< 8000 characters) that CHARINDEX can be used on them. Then the same algorithm from Erland's split string is applied.

Note that this function does not gracefully handle situations such as passing in the wrong delimiter. So please carefully test your code before deploying this!

Using the function is quite simple:

 

SELECT * 
FROM dbo.SplitString('something, something else, etc, etc, etc...', ',')

 


Update, February 15, 2005: Fixed so that only 8000 numbers are needed in the Numbers table for this to work. Previously required as many numbers as were present in the string to be split.



Published Wednesday, July 12, 2006 10:20 PM by Adam Machanic

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Tiraj said:

Well it says "Using the function is quite simple"

But im having problems (errors) even while tring to create the function...

March 14, 2007 2:15 AM
 

Adam Machanic said:

What error are you seeing?  It works fine on this end...

March 18, 2007 12:13 PM
 

Ali said:

It works fine. but when I use it in a Stored Procedure it gives error:

Incorrect syntax near 'SplitString'.

April 19, 2007 2:22 AM
 

Asghar said:

Hi Adam this is a great function but I have got string with such as ("hello","sdfsfs",....)

My problem is how can I pass two parremeters such as , and "".

and how can I insert the values into a table

Thanks

November 28, 2007 11:55 PM
 

David said:

Had to change the last section of the code to get it to work beyond 8,000 characters.  Great approach though.

_________________________________

--Start next chunk

SET @SplitStart = @SplitEnd + 1

SET @SplitEnd = @SplitEnd + 7998

IF ( @SplitEnd >= DATALENGTH(@List)   )

  SET @SplitEnd = DATALENGTH(@List) +1

ELSE

BEGIN

 SELECT @SplitEnd = @SplitStart + MAX(Number)

 FROM dbo.Numbers

 WHERE (SUBSTRING(@List, Number, 1) = @Delimiter

 OR Number = DATALENGTH(@List) + 1

  )

AND Number BETWEEN @SplitStart AND @SplitEnd

END

February 5, 2008 4:07 PM
 

David said:

Please ignore the previous post - that didn't fix it.  The issue seemed to be with parsing the last number in the last chunk.  I added

    AND CHARINDEX(',', @LeftSplit, Number + 1) > 0

to the key SELECT statement.

February 5, 2008 4:36 PM

Leave a Comment

(required) 
(optional)
(required) 
Submit

About Adam Machanic

Adam Machanic is a Boston-based independent database consultant, writer, and speaker. He has been involved in dozens of SQL Server implementations for both high-availability OLTP and large-scale data warehouse applications, and has optimized data access layer performance for several data-intensive applications. Adam has written for numerous web sites and magazines, including SQLblog, Simple Talk, Search SQL Server, SQL Server Professional, CoDe, and VSJ. He has also contributed to several books on SQL Server, including "Expert SQL Server 2005 Development" (Apress, 2007) and "Inside SQL Server 2005: Query Tuning and Optimization" (Microsoft Press, 2007). Adam regularly speaks at user groups, community events, and conferences on a variety of SQL Server and .NET-related topics. He is a Microsoft Most Valuable Professional (MVP) for SQL Server and a Microsoft Certified IT Professional (MCITP).
Powered by Community Server (Commercial Edition), by Telligent Systems
  Privacy Statement