sql-serversql-server-2008t-sqlsplit

Using T-SQL, return nth delimited element from a string


I have a need to create a function the will return nth element of a delimited string.

For a data migration project, I am converting JSON audit records stored in a SQL Server database into a structured report using SQL script. Goal is to deliver a sql script and a sql function used by the script without any code.

(This is a short-term fix will be used while a new auditing feature is added the ASP.NET/MVC application)

There is no shortage of delimited string to table examples available. I've chosen a Common Table Expression example http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings

Example: I want to return 67 from '1,222,2,67,888,1111'


Solution

  • Here is my initial solution... It is based on work by Aaron Bertrand http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings

    I simply changed the return type to make it a scalar function.

    Example: SELECT dbo.GetSplitString_CTE('1,222,2,67,888,1111',',',4)

    CREATE FUNCTION dbo.GetSplitString_CTE
    (
       @List       VARCHAR(MAX),
       @Delimiter  VARCHAR(255),
       @ElementNumber int
    )
    RETURNS VARCHAR(4000)
    AS
    BEGIN
    
       DECLARE @result varchar(4000)    
       DECLARE @Items TABLE ( position int IDENTITY PRIMARY KEY,
                              Item VARCHAR(4000)
                             )  
    
       DECLARE @ll INT = LEN(@List) + 1, @ld INT = LEN(@Delimiter);  
    
       WITH a AS
       (
           SELECT
               [start] = 1,
               [end]   = COALESCE(NULLIF(CHARINDEX(@Delimiter, 
                           @List, @ld), 0), @ll),
               [value] = SUBSTRING(@List, 1, 
                         COALESCE(NULLIF(CHARINDEX(@Delimiter, 
                           @List, @ld), 0), @ll) - 1)
           UNION ALL
           SELECT
               [start] = CONVERT(INT, [end]) + @ld,
               [end]   = COALESCE(NULLIF(CHARINDEX(@Delimiter, 
                           @List, [end] + @ld), 0), @ll),
               [value] = SUBSTRING(@List, [end] + @ld, 
                         COALESCE(NULLIF(CHARINDEX(@Delimiter, 
                           @List, [end] + @ld), 0), @ll)-[end]-@ld)
           FROM a
           WHERE [end] < @ll
       )
       INSERT @Items SELECT [value]
       FROM a
       WHERE LEN([value]) > 0
       OPTION (MAXRECURSION 0);
    
       SELECT @result=Item
       FROM @Items
       WHERE position=@ElementNumber
    
       RETURN @result;
    END
    GO