• Very nice and well explained article, I enjoyed reading it and just wanted to add my findings which include handling the case where the string to be parsed is blank. In this instance I would expect to get no rows back but the solution in this article seems to return a row with a blank string.

    Here's the version I've been using for a while now and it seems to match performance with yours with the included handling of a blank source string.

    I also use the values method of a row generator/tally table as I don't need to support prior to 2008 and it makes it more readable IMO.

    ;with e(n) as ( select 0 from (values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) T(n))

    ,rg(n) as (select 0 from e,e e2,e e3,e e4)

    select Item=substring(@pString,n,isnull(nullif(CHARINDEX(@pDelimiter,@pString,n),0),len(@pString)+1)-n)

    from (

    select n=1 where len(@pString) > 0

    union all

    select n+1 from (select top(len(@pString)) n=ROW_NUMBER() over (order by (select null)) from rg) T where SUBSTRING(@pString,n,1) = @pDelimiter

    ) StartPositions