Skip to main content

SQL Server function to split a delimited string into a 2 column table.

-- ==========================================================================
-- SQL Server function to split a delimted string list into a 2 column table
-- (1. Index, 2. Value).
--
-- f_SplitString: Table-valued Function
-- f_StringLen: Scalar-valued Function
--
-- USAGE:
--      declare @str nvarchar(400) = N'name, age\, email, something here, another field';
--      select [Index] as idx, [Value] as val from dbo.f_SplitString(@str, ',', '\', '');
-- ==========================================================================

PRINT '';
PRINT '';
PRINT 'Creating function f_StringLen...';
GO
CREATE FUNCTION dbo.f_StringLen(@String nvarchar(4000))
RETURNS int
BEGIN
RETURN LEN(@String + '|') - 1;
END;
GO

PRINT '';
PRINT 'Creating function f_SplitString...';
GO
CREATE FUNCTION dbo.f_SplitString(@String nvarchar(4000), @Separator char, @Escape char, @NullPlaceholder char)
RETURNS @SubString TABLE([Index] int PRIMARY KEY IDENTITY, [Value] nvarchar(4000))
BEGIN

DECLARE @ForceError int;
DECLARE @StringLen int;
DECLARE @CurStringIndex smallint;
DECLARE @CurSubString nvarchar(4000);
DECLARE @CurChar char;
DECLARE @NextChar char;

SET @StringLen = dbo.f_StringLen(@String);
SET @CurStringIndex = 1;
SET @CurSubString = '';
SET @NextChar = SUBSTRING(@String, @CurStringIndex, 1);

WHILE @CurStringIndex <= @StringLen + 1
BEGIN
    SET @CurChar = @NextChar;
    SET @NextChar = CASE
                    WHEN @CurStringIndex < @StringLen THEN SUBSTRING(@String, @CurStringIndex + 1, 1)
                    ELSE NULL
                    END;

    IF @CurChar = @Separator OR @CurStringIndex > @StringLen
    BEGIN
        INSERT INTO @SubString
        VALUES(@CurSubstring);
        SET @CurSubString = '';
    END;
    ELSE
    BEGIN
        IF @CurChar = @Escape
        BEGIN
            SET @CurStringIndex = @CurStringIndex + 1;
            SET @CurChar = @NextChar;
            SET @NextChar = CASE
                            WHEN @CurStringIndex < @StringLen THEN SUBSTRING(@String, @CurStringIndex + 1, 1)
                            ELSE NULL
                            END;

            IF @CurChar IS NULL
            BEGIN
                -- The string ended with an escape character.
                SET @ForceError = 1 / 0;
            END;
            IF @CurChar = @NullPlaceholder
            BEGIN
                IF @CurSubString != '' OR
                   @NextChar != @Separator AND
                   @NextChar IS NOT NULL
                BEGIN
                    -- The null value escape sequence may only appear as the entirety of a substring.
                    SET @ForceError = 1 / 0;
                END;

                INSERT INTO @SubString
                VALUES(NULL);

                SET @CurStringIndex = @CurStringIndex + 1;
                SET @CurChar = @NextChar;
                SET @NextChar = CASE
                                WHEN @CurStringIndex < @StringLen THEN SUBSTRING(@String, @CurStringIndex + 1, 1)
                                ELSE NULL
                                END;
            END;
            ELSE
            BEGIN
                IF @CurChar IN(@Escape, @Separator)
                BEGIN
                    SET @CurSubString = @CurSubString + @CurChar;
                END;
                ELSE
                BEGIN
                    -- Unrecognized escape sequence - ie., the escape
                    -- character was followed by something other than
                    -- @Escape, @Separator, or @NullPlaceholder
                    SET @ForceError = 1 / 0;
                END;
            END;
        END;
        ELSE
        BEGIN
            -- No escape
            SET @CurSubString = @CurSubString + @CurChar;
        END;
    END;

    SET @CurStringIndex = @CurStringIndex + 1;
END;
    RETURN;

    END;
GO