Click here to Skip to main content
15,879,095 members
Articles / Database Development / SQL Server / SQL Server 2014
Tip/Trick

SQL Server: Doing String Split And Join

Rate me:
Please Sign up or sign in to vote.
5.00/5 (8 votes)
19 Feb 2019CPOL1 min read 24.8K   57   7   6
How to do string split and join in SQL Server

Introduction

String splitting and joining are common in most programming languages like C#, JAVA, PHP. But I did not find any option in SQL SERVER. Let's create some code to do the same in SQL Server database.

It is always good to know a few things like CONVERT, STUFF, CHARINDEX, SUBSTRING, LTRIM, RTRIM, XML PATH() while working with string objects in SQL Server.

Join: List to List String

Here, we are going to convert (1), (2), (3), (4), (NULL) table values to NULL,1,2,3,4 string.

SQL
DECLARE @tblId TABLE (Id BIGINT NULL);
INSERT INTO @tblId VALUES (1), (2), (3), (4), (NULL);
SELECT * FROM @tblId;

DECLARE @separator NVARCHAR(10) = ',';
SELECT STUFF((SELECT @separator + COALESCE(CONVERT(NVARCHAR(MAX), Id), 'NULL') 
              FROM @tblId        /*to deselect NULL, add WHERE condition*/
              ORDER BY Id
              FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)')
              , 1, 1, '') AS Ids;

Usage Like AGGREGATE Function

SQL
DECLARE @tblUserGroup TABLE (GroupId INT, UserId INT NULL);
INSERT INTO @tblUserGroup VALUES
(1, 1), (1, 2), (1, 3),
(2, 4), (2, 5), (2, 6),
(3, NULL);
SELECT * FROM @tblUserGroup;

DECLARE @separator CHAR = ',';
SELECT 
    GroupId, 
    COUNT(UserId) AS TotalUser,
    STUFF((SELECT @separator + CONVERT(NVARCHAR(MAX), UserId) 
            FROM @tblUserGroup AS uc
            WHERE uc.GroupId = g.GroupId        /*to deselect NULL, add WHERE condition*/
            ORDER BY UserId
            FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)')
            , 1, 1, '') AS UserIds
FROM @tblUserGroup AS g
GROUP BY GroupId

Function with a user-defined type is another option, but again, we have to declare variable tables. But it would be better if we can create an AGGREGATE function or CLR.

Split: List String to List

This feature is now defaulted as STRING_SPLIT at SQL Servers starting from 2016 https://docs.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql?view=sql-server-2017.

But for the old versions, we can do:

SQL
DECLARE @valueList NVARCHAR(MAX) = 'Dan, Han, Mos, Ben,, ,null, Null, NULL';
DECLARE @separator NVARCHAR(10) = ',';

/*split process*/
DECLARE @tblValue TABLE(Value NVARCHAR(MAX));
DECLARE @fromIndex INT, @seperatiorAtIndex INT, @value NVARCHAR(100);
SET @fromIndex = 1;
SET @seperatiorAtIndex = CHARINDEX(@separator, @valueList)

WHILE @fromIndex < LEN(@valueList) + 1
BEGIN
    IF @seperatiorAtIndex = 0  
        SET @seperatiorAtIndex = LEN(@valueList) + 1
    SET @value = LTRIM(RTRIM(SUBSTRING_
                 (@valueList, @fromIndex, @seperatiorAtIndex - @fromIndex))); 
   
    INSERT INTO @tblValue VALUES(@value) -- inserting to the table  
   
    SET @fromIndex = @seperatiorAtIndex + 1
    SET @seperatiorAtIndex = CHARINDEX(@separator, @valueList, @fromIndex)  
END

Result:

SQL
/*result*/
SELECT * FROM @tblValue;
SELECT Value FROM @tblValue;

Exclude null or empty:

SQL
SELECT * FROM @tblValue
WHERE LTRIM(RTRIM(UPPER(Value))) NOT IN ('', 'NULL');    /*exclude null or empty*/

Create Table-Valued FUNCTION

Here, we are going to create a helper function:

SQL
/*create table-valued function*/
CREATE FUNCTION fnSplit(@valueList NVARCHAR(MAX), @separator NVARCHAR(10))
RETURNS @tblValue TABLE(Value NVARCHAR(MAX))
AS 
BEGIN
    /*split process*/
    DECLARE @fromIndex INT, @seperatiorAtIndex INT, @value NVARCHAR(100);
    SET @fromIndex = 1;
    SET @seperatiorAtIndex = CHARINDEX(@separator, @valueList)

    WHILE @fromIndex < LEN(@valueList) + 1
    BEGIN
           IF @seperatiorAtIndex = 0  
               SET @seperatiorAtIndex = LEN(@valueList) + 1
           SET @value = LTRIM(RTRIM(SUBSTRING_
               (@valueList, @fromIndex, @seperatiorAtIndex - @fromIndex))); 
  
           INSERT INTO @tblValue VALUES(@value) -- inserting to the table  
   
           SET @fromIndex = @seperatiorAtIndex + 1
           SET @seperatiorAtIndex = CHARINDEX(@separator, @valueList, @fromIndex)  
    END

    RETURN
END;

Using this helper function like:

SQL
/*using that function*/
DECLARE @valueList NVARCHAR(MAX) = 'Dan, Han, Mos, Ben';
DECLARE @separator NVARCHAR(10) = ',';
SELECT Value FROM fnSplit(@valueList, @separator);

Please find the necessary SQL files as an attachment. Rather than running the whole script altogether, run it section wise.

Split: Single Row to Multiple Rows

Here, we are splitting Roles column value and populating multiple rows form a single row.

SQL
DECLARE @tblSettings TABLE (
    Id INT IDENTITY(1, 1),
    StoreId INT,
    Roles VARCHAR(MAX) NULL
);
INSERT INTO @tblSettings (StoreId, [Roles])
VALUES
(10, 'A, B,C , , D ,'),
(20, ''),
(30, NULL);
SELECT * FROM @tblSettings;

WITH
RoleNamesSettingSplitted(Id, StoreId, RoleName, RemainingRoleNames) AS
(
    /*recursion, may need to use OPTION(MAXRECURSION 0) at client*/
    SELECT
        Id,
        StoreId,
        LTRIM(RTRIM(CAST(LEFT(Roles, CHARINDEX(',', Roles + ',') - 1) AS VARCHAR(MAX)))),
        CAST (STUFF(Roles, 1, CHARINDEX(',', Roles + ','), '') AS VARCHAR(MAX))
    FROM @tblSettings 
    WHERE Roles IS NOT NULL AND LTRIM(RTRIM(Roles)) <> ''
    UNION ALL
    SELECT
        Id,
        StoreId,
        LTRIM(RTRIM(CAST(LEFT(RemainingRoleNames, _
              CHARINDEX(',', RemainingRoleNames + ',') - 1) AS VARCHAR(MAX)))),
        CAST (STUFF(RemainingRoleNames, 1, _
              CHARINDEX(',', RemainingRoleNames + ','), '') AS VARCHAR(MAX))
    FROM RoleNamesSettingSplitted
    WHERE LTRIM(RTRIM(RemainingRoleNames)) > ''
)
SELECT 
    Id,
    StoreId,
    RoleName
FROM RoleNamesSettingSplitted
WHERE LEN(RoleName) > 0                /*ignore empty values*/
GROUP BY Id, StoreId, RoleName        /*ignore duplicates*/
--OPTION(MAXRECURSION 0)

This query in doing recursion calls. Depending on list size, we may need to include OPTION(MAXRECURSION 0) in the query.

History

  • 19th February, 2019: Initial version
  • 23rd June, 2023: Second version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Bangladesh Bangladesh
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseVery helpful Pin
coder_ak25-Feb-19 9:56
coder_ak25-Feb-19 9:56 
GeneralRe: Very helpful Pin
DiponRoy3-Apr-20 7:00
DiponRoy3-Apr-20 7:00 
QuestionOther Methods For Consideration Pin
JonathanFahey20-Feb-19 9:36
JonathanFahey20-Feb-19 9:36 
AnswerRe: Other Methods For Consideration Pin
DiponRoy21-Feb-19 23:12
DiponRoy21-Feb-19 23:12 
QuestionNice Article Pin
Member 1324062619-Feb-19 21:53
Member 1324062619-Feb-19 21:53 
AnswerRe: Nice Article Pin
DiponRoy21-Feb-19 23:14
DiponRoy21-Feb-19 23:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.