Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/87.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
T-SQL拆分字符串_Sql_Sql Server_Tsql_Sql Server 2008_Split - Fatal编程技术网

T-SQL拆分字符串

T-SQL拆分字符串,sql,sql-server,tsql,sql-server-2008,split,Sql,Sql Server,Tsql,Sql Server 2008,Split,我有一个SQL Server 2008 R2列,其中包含一个字符串,需要用逗号分隔。我在StackOverflow上看到了很多答案,但没有一个在R2中有效。我已确保对任何拆分函数示例具有选择权限。非常感谢您的帮助。我以前使用过此SQL,它可能适用于您:- CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) ) RETURNS @returnList TABLE ([Name] [nvarchar] (500)) AS BE

我有一个SQL Server 2008 R2列,其中包含一个字符串,需要用逗号分隔。我在StackOverflow上看到了很多答案,但没有一个在R2中有效。我已确保对任何拆分函数示例具有选择权限。非常感谢您的帮助。

我以前使用过此SQL,它可能适用于您:-

CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )
RETURNS
 @returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE CHARINDEX(',', @stringToSplit) > 0
 BEGIN
  SELECT @pos  = CHARINDEX(',', @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END

 INSERT INTO @returnList
 SELECT @stringToSplit

 RETURN
END
使用它:-

SELECT * FROM dbo.splitstring('91,12,65,78,56,789')
如果你更换

WHILE CHARINDEX(',', @stringToSplit) > 0

您可以消除while循环之后的最后一次插入

CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )
RETURNS
 @returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE LEN(@stringToSplit) > 0
 BEGIN
  SELECT @pos  = CHARINDEX(',', @stringToSplit)


if @pos = 0
        SELECT @pos = LEN(@stringToSplit)


  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END

 RETURN
END

我最近不得不写这样的东西。这是我想出的解决办法。它适用于任何分隔符字符串,我认为它的性能会稍好一些:

CREATE FUNCTION [dbo].[SplitString] 
    ( @string nvarchar(4000)
    , @delim nvarchar(100) )
RETURNS
    @result TABLE 
        ( [Value] nvarchar(4000) NOT NULL
        , [Index] int NOT NULL )
AS
BEGIN
    DECLARE @str nvarchar(4000)
          , @pos int 
          , @prv int = 1

    SELECT @pos = CHARINDEX(@delim, @string)
    WHILE @pos > 0
    BEGIN
        SELECT @str = SUBSTRING(@string, @prv, @pos - @prv)
        INSERT INTO @result SELECT @str, @prv

        SELECT @prv = @pos + LEN(@delim)
             , @pos = CHARINDEX(@delim, @string, @pos + 1)
    END

    INSERT INTO @result SELECT SUBSTRING(@string, @prv, 4000), @prv
    RETURN
END

一个使用CTE的解决方案,如果有人需要的话(除了我,我显然需要,这就是我为什么写它的原因)

ALTER函数[dbo].func\u split\u字符串
(
@输入为varchar(最大值),
@分隔符为varchar(10)=“;”
)
返回@result表
(
id smallint恒等式(1,1),
csv_值varchar(最大值)不为空
)
作为
开始
声明@pos为INT;
将@string声明为VARCHAR(MAX)='';
而LEN(@input)>0
开始
选择@pos=CHARINDEX(@delimiter,@input);

IF(@pos而不是递归CTE和while循环,有人考虑过更基于集合的方法吗?请注意,此函数是针对这个问题编写的,它基于SQL Server 2008,并且逗号作为分隔符。。在SQL Server 2016及更高版本中(以及在兼容级别130及更高版本中)

但您必须将
选项(MAXRECURSION 0)
(或
MAXRECURSION
)附加到外部查询,以避免字符串递归超过100个字符时出现错误。如果这也是一个不好的选择,请参见注释中指出的


(此外,分隔符必须是
NCHAR(这是更窄的裁剪。当我这样做时,我通常有一个逗号分隔的唯一ID列表(INT或BIGINT),我希望将其转换为一个表,用作主键为INT或BIGINT的另一个表的内部联接。我希望返回一个内联表值函数,以便获得尽可能高效的联接

示例用法为:

 DECLARE @IDs VARCHAR(1000);
 SET @IDs = ',99,206,124,8967,1,7,3,45234,2,889,987979,';
 SELECT me.Value
 FROM dbo.MyEnum me
 INNER JOIN dbo.GetIntIdsTableFromDelimitedString(@IDs) ids ON me.PrimaryKey = ids.ID
我从中窃取了这个想法,将其更改为内联表值并转换为INT

create function dbo.GetIntIDTableFromDelimitedString
    (
    @IDs VARCHAR(1000)  --this parameter must start and end with a comma, eg ',123,456,'
                        --all items in list must be perfectly formatted or function will error
)
RETURNS TABLE AS
 RETURN

SELECT
    CAST(SUBSTRING(@IDs,Nums.number + 1,CHARINDEX(',',@IDs,(Nums.number+2)) - Nums.number - 1) AS INT) AS ID 
FROM   
     [master].[dbo].[spt_values] Nums
WHERE Nums.Type = 'P' 
AND    Nums.number BETWEEN 1 AND DATALENGTH(@IDs)
AND    SUBSTRING(@IDs,Nums.number,1) = ','
AND    CHARINDEX(',',@IDs,(Nums.number+1)) > Nums.number;

GO

这是一个可以使用patindex在模式上拆分的版本,这是对上面文章的简单改编


alter FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(1000), @splitPattern varchar(10) )
RETURNS
 @returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE PATINDEX(@splitPattern, @stringToSplit) > 0
 BEGIN
  SELECT @pos  = PATINDEX(@splitPattern, @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END

 INSERT INTO @returnList
 SELECT @stringToSplit

 RETURN
END
select * from dbo.splitstring('stringa/stringb/x,y,z','%[/,]%');
结果是这样的

斯特林加 斯特林布 x Y
z

我需要一种快速的方法从邮政编码中去掉
+4

UPDATE #Emails 
  SET ZIPCode = SUBSTRING(ZIPCode, 1, (CHARINDEX('-', ZIPCODE)-1)) 
  WHERE ZIPCode LIKE '%-%'
没有proc…没有UDF…只有一个紧凑的内联命令,它可以做它必须做的事情。不花哨,不优雅


根据需要更改分隔符等,它将适用于任何情况。

人员我通常使用此功能:

ALTER FUNCTION [dbo].[CUST_SplitString]
(
    @String NVARCHAR(4000),
    @Delimiter NCHAR(1)
)
RETURNS TABLE 
AS
RETURN 
(
    WITH Split(stpos,endpos) 
    AS(
        SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos
        UNION ALL
        SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1) 
        FROM Split
        WHERE endpos > 0
    )
    SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
        'Data' = SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)-stpos)
    FROM Split
)

我已经根据要求开发了一个双拆分器(使用两个拆分字符)。在这个线程中可能会有一些价值,因为它是与字符串拆分相关的查询中引用最多的

CREATE FUNCTION uft_DoubleSplitter 
(   
    -- Add the parameters for the function here
    @String VARCHAR(4000), 
    @Splitter1 CHAR,
    @Splitter2 CHAR
)
RETURNS @Result TABLE (Id INT,MId INT,SValue VARCHAR(4000))
AS
BEGIN
DECLARE @FResult TABLE(Id INT IDENTITY(1, 1),
                   SValue VARCHAR(4000))
DECLARE @SResult TABLE(Id INT IDENTITY(1, 1),
                   MId INT,
                   SValue VARCHAR(4000))
SET @String = @String+@Splitter1

WHILE CHARINDEX(@Splitter1, @String) > 0
    BEGIN
       DECLARE @WorkingString VARCHAR(4000) = NULL

       SET @WorkingString = SUBSTRING(@String, 1, CHARINDEX(@Splitter1, @String) - 1)
       --Print @workingString

       INSERT INTO @FResult
       SELECT CASE
            WHEN @WorkingString = '' THEN NULL
            ELSE @WorkingString
            END

       SET @String = SUBSTRING(@String, LEN(@WorkingString) + 2, LEN(@String))

    END
IF ISNULL(@Splitter2, '') != ''
    BEGIN
       DECLARE @OStartLoop INT
       DECLARE @OEndLoop INT

       SELECT @OStartLoop = MIN(Id),
            @OEndLoop = MAX(Id)
       FROM @FResult

       WHILE @OStartLoop <= @OEndLoop
          BEGIN
             DECLARE @iString VARCHAR(4000)
             DECLARE @iMId INT

             SELECT @iString = SValue+@Splitter2,
                   @iMId = Id
             FROM @FResult
             WHERE Id = @OStartLoop

             WHILE CHARINDEX(@Splitter2, @iString) > 0
                BEGIN
                    DECLARE @iWorkingString VARCHAR(4000) = NULL

                    SET @IWorkingString = SUBSTRING(@iString, 1, CHARINDEX(@Splitter2, @iString) - 1)

                    INSERT INTO @SResult
                    SELECT @iMId,
                         CASE
                         WHEN @iWorkingString = '' THEN NULL
                         ELSE @iWorkingString
                         END

                    SET @iString = SUBSTRING(@iString, LEN(@iWorkingString) + 2, LEN(@iString))

                END

             SET @OStartLoop = @OStartLoop + 1
          END
       INSERT INTO @Result
       SELECT MId AS PrimarySplitID,
            ROW_NUMBER() OVER (PARTITION BY MId ORDER BY Mid, Id) AS SecondarySplitID ,
            SValue
       FROM @SResult
    END
ELSE
    BEGIN
       INSERT INTO @Result
       SELECT Id AS PrimarySplitID,
            NULL AS SecondarySplitID,
            SValue
       FROM @FResult
    END
RETURN
可能的用法(获取每个分割的第二个值):

--FirstSplit
SELECT * FROM uft_DoubleSplitter('ValueA=ValueB=ValueC=ValueD==ValueE&ValueA=ValueB=ValueC===ValueE&ValueA=ValueB==ValueD===','&',NULL)

--Second Split
SELECT * FROM uft_DoubleSplitter('ValueA=ValueB=ValueC=ValueD==ValueE&ValueA=ValueB=ValueC===ValueE&ValueA=ValueB==ValueD===','&','=')
SELECT fn.SValue
FROM uft_DoubleSplitter('ValueA=ValueB=ValueC=ValueD==ValueE&ValueA=ValueB=ValueC===ValueE&ValueA=ValueB==ValueD===', '&', '=')AS fn
WHERE fn.mid = 2

最简单的方法是使用
XML
格式

1.将字符串转换为不带表的行

查询

DECLARE @String varchar(100) = 'String1,String2,String3'
-- To change ',' to any other delimeter, just change ',' to your desired one
DECLARE @Delimiter CHAR = ','    

SELECT LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'Value' 
FROM  
(     
     SELECT CAST ('<M>' + REPLACE(@String, @Delimiter, '</M><M>') + '</M>' AS XML) AS Data            
) AS A 
CROSS APPLY Data.nodes ('/M') AS Split(a)
-- To change ',' to any other delimeter, just change ',' before '</M><M>' to your desired one
DECLARE @Delimiter CHAR = ','

SELECT ID,LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'Value' 
FROM  
(     
     SELECT ID,CAST ('<M>' + REPLACE(VALUE, @Delimiter, '</M><M>') + '</M>' AS XML) AS Data            
     FROM TABLENAME
) AS A 
CROSS APPLY Data.nodes ('/M') AS Split(a)
2.从每个CSV行都有ID的表转换为行

源表

 x-----x--------------------------x
 | Id  |           Value          |
 x-----x--------------------------x
 |  1  |  String1,String2,String3 |
 |  2  |  String4,String5,String6 |     
 x-----x--------------------------x
查询

DECLARE @String varchar(100) = 'String1,String2,String3'
-- To change ',' to any other delimeter, just change ',' to your desired one
DECLARE @Delimiter CHAR = ','    

SELECT LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'Value' 
FROM  
(     
     SELECT CAST ('<M>' + REPLACE(@String, @Delimiter, '</M><M>') + '</M>' AS XML) AS Data            
) AS A 
CROSS APPLY Data.nodes ('/M') AS Split(a)
-- To change ',' to any other delimeter, just change ',' before '</M><M>' to your desired one
DECLARE @Delimiter CHAR = ','

SELECT ID,LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'Value' 
FROM  
(     
     SELECT ID,CAST ('<M>' + REPLACE(VALUE, @Delimiter, '</M><M>') + '</M>' AS XML) AS Data            
     FROM TABLENAME
) AS A 
CROSS APPLY Data.nodes ('/M') AS Split(a)

这里有一个正确的版本,但我认为最好添加一点容错性,以防它们有一个尾随逗号,并使其成为一个函数,而不是一个更大的代码段的一部分。以防您只使用它一次,不需要函数。这也适用于整数(这就是我需要它的原因)因此您可能必须更改数据类型

DECLARE @StringToSeperate VARCHAR(10)
SET @StringToSeperate = '1,2,5'

--SELECT @StringToSeperate IDs INTO #Test

DROP TABLE #IDs
CREATE TABLE #IDs (ID int) 

DECLARE @CommaSeperatedValue NVARCHAR(255) = ''
DECLARE @Position INT = LEN(@StringToSeperate)

--Add Each Value
WHILE CHARINDEX(',', @StringToSeperate) > 0
BEGIN
    SELECT @Position  = CHARINDEX(',', @StringToSeperate)  
    SELECT @CommaSeperatedValue = SUBSTRING(@StringToSeperate, 1, @Position-1)

    INSERT INTO #IDs 
    SELECT @CommaSeperatedValue

    SELECT @StringToSeperate = SUBSTRING(@StringToSeperate, @Position+1, LEN(@StringToSeperate)-@Position)

END

--Add Last Value
IF (LEN(LTRIM(RTRIM(@StringToSeperate)))>0)
BEGIN
    INSERT INTO #IDs
    SELECT SUBSTRING(@StringToSeperate, 1, @Position)
END

SELECT * FROM #IDs

我稍微修改了+Andy Robinson的函数。现在您可以从返回表中仅选择所需的部分:

CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )

RETURNS

 @returnList TABLE ([numOrder] [tinyint] , [Name] [nvarchar] (500)) AS
BEGIN

 DECLARE @name NVARCHAR(255)

 DECLARE @pos INT

 DECLARE @orderNum INT

 SET @orderNum=0

 WHILE CHARINDEX('.', @stringToSplit) > 0

 BEGIN
    SELECT @orderNum=@orderNum+1;
  SELECT @pos  = CHARINDEX('.', @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @orderNum,@name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END
    SELECT @orderNum=@orderNum+1;
 INSERT INTO @returnList
 SELECT @orderNum, @stringToSplit

 RETURN
END


Usage:
从dbo.splitstring('ELIS.YD.CRP1.1.CBA.MDSP.T389.BT')中选择名称,其中numOrder=5

您可以使用此功能:

        CREATE FUNCTION SplitString
        (    
           @Input NVARCHAR(MAX),
           @Character CHAR(1)
          )
            RETURNS @Output TABLE (
            Item NVARCHAR(1000)
          )
        AS
        BEGIN

      DECLARE @StartIndex INT, @EndIndex INT
      SET @StartIndex = 1
      IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character
      BEGIN
            SET @Input = @Input + @Character
      END

      WHILE CHARINDEX(@Character, @Input) > 0
      BEGIN
            SET @EndIndex = CHARINDEX(@Character, @Input)

            INSERT INTO @Output(Item)
            SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1)

            SET @Input = SUBSTRING(@Input, @EndIndex + 1, LEN(@Input))
      END

      RETURN
END
GO
创建函数拆分字符串
(    
@输入NVARCHAR(最大值),
@字符字符(1)
)
返回@Output表(
项目NVARCHAR(1000)
)
作为
开始
声明@StartIndex INT、@EndIndex INT
设置@StartIndex=1
如果子字符串(@Input,LEN(@Input)-1,LEN(@Input))@字符
开始
设置@Input=@Input+@字符
结束
而CHARINDEX(@Character,@Input)>0
开始
设置@EndIndex=CHARINDEX(@Character,@Input)
插入@Output(项目)
选择子字符串(@Input、@StartIndex、@EndIndex-1)
设置@Input=SUBSTRING(@Input,@EndIndex+1,LEN(@Input))
结束
返回
结束
去
最简单的方法:

  • 安装SQL Server 2016
  • 使用字符串分割

  • 它甚至在express edition中也能工作:)。

    终于在SQL Server 2016中结束了等待
    他们引入了拆分字符串功能:

    所有其他分割字符串的方法,如XML、Tally table、while loop等,都被这个
    string\u split
    函数吹走了


    这是一篇关于性能比较的优秀文章:

    这是一个示例,您可以将其用作函数,也可以将相同的逻辑放入过程中。 --从[dbo].fn\u SplitString;中选择*

    CREATE FUNCTION [dbo].[fn_SplitString]
    (@CSV VARCHAR(MAX), @Delimeter VARCHAR(100) = ',')
           RETURNS @retTable TABLE 
    (
    
        [value] VARCHAR(MAX) NULL
    )AS
    
    BEGIN
    
    DECLARE
           @vCSV VARCHAR (MAX) = @CSV,
           @vDelimeter VARCHAR (100) = @Delimeter;
    
    IF @vDelimeter = ';'
    BEGIN
        SET @vCSV = REPLACE(@vCSV, ';', '~!~#~');
        SET @vDelimeter = REPLACE(@vDelimeter, ';', '~!~#~');
    END;
    
    SET @vCSV = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@vCSV, '&', '&amp;'), '<', '&lt;'), '>', '&gt;'), '''', '&apos;'), '"', '&quot;');
    
    DECLARE @xml XML;
    
    SET @xml = '<i>' + REPLACE(@vCSV, @vDelimeter, '</i><i>') + '</i>';
    
    INSERT INTO @retTable
    SELECT
           x.i.value('.', 'varchar(max)') AS COLUMNNAME
      FROM @xml.nodes('//i')AS x(i);
    
     RETURN;
    END;
    
    创建函数[dbo]。[fn\u SplitString]
    (@CSV VARCHAR(最大值),@Delimeter VARCHAR(100)=',')
    返回@retTable表
    (
    [值]VARCHAR(最大值)NULL
    )作为
    开始
    声明
    @vCSV VARCHAR(最大值)=@CSV,
    @vDelimeter VARCHAR(100)=@Delimeter;
    如果@vDelimeter=';'
    开始
    设置@vCSV=REPLACE(@vCSV,“;”,“~!~”);
    设置@vDelimeter=REPLACE(@vDelimeter,“;”,“~!~#~”);
    结束;
    设置@vCSV=REPLACE(REPLACE(REPLACE)(REPLACE(REPLACE)(@vCSV,,,,,,,,,,,,,,,,,);
    声明@xmlx
    
     x-----x----------x
     | Id  |  Value   |
     x-----x----------x
     |  1  |  String1 |
     |  1  |  String2 |  
     |  1  |  String3 |
     |  2  |  String4 |  
     |  2  |  String5 |
     |  2  |  String6 |     
     x-----x----------x
    
    DECLARE @StringToSeperate VARCHAR(10)
    SET @StringToSeperate = '1,2,5'
    
    --SELECT @StringToSeperate IDs INTO #Test
    
    DROP TABLE #IDs
    CREATE TABLE #IDs (ID int) 
    
    DECLARE @CommaSeperatedValue NVARCHAR(255) = ''
    DECLARE @Position INT = LEN(@StringToSeperate)
    
    --Add Each Value
    WHILE CHARINDEX(',', @StringToSeperate) > 0
    BEGIN
        SELECT @Position  = CHARINDEX(',', @StringToSeperate)  
        SELECT @CommaSeperatedValue = SUBSTRING(@StringToSeperate, 1, @Position-1)
    
        INSERT INTO #IDs 
        SELECT @CommaSeperatedValue
    
        SELECT @StringToSeperate = SUBSTRING(@StringToSeperate, @Position+1, LEN(@StringToSeperate)-@Position)
    
    END
    
    --Add Last Value
    IF (LEN(LTRIM(RTRIM(@StringToSeperate)))>0)
    BEGIN
        INSERT INTO #IDs
        SELECT SUBSTRING(@StringToSeperate, 1, @Position)
    END
    
    SELECT * FROM #IDs
    
    CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )
    
    RETURNS
    
     @returnList TABLE ([numOrder] [tinyint] , [Name] [nvarchar] (500)) AS
    BEGIN
    
     DECLARE @name NVARCHAR(255)
    
     DECLARE @pos INT
    
     DECLARE @orderNum INT
    
     SET @orderNum=0
    
     WHILE CHARINDEX('.', @stringToSplit) > 0
    
     BEGIN
        SELECT @orderNum=@orderNum+1;
      SELECT @pos  = CHARINDEX('.', @stringToSplit)  
      SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)
    
      INSERT INTO @returnList 
      SELECT @orderNum,@name
    
      SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
     END
        SELECT @orderNum=@orderNum+1;
     INSERT INTO @returnList
     SELECT @orderNum, @stringToSplit
    
     RETURN
    END
    
    
    Usage:
    
            CREATE FUNCTION SplitString
            (    
               @Input NVARCHAR(MAX),
               @Character CHAR(1)
              )
                RETURNS @Output TABLE (
                Item NVARCHAR(1000)
              )
            AS
            BEGIN
    
          DECLARE @StartIndex INT, @EndIndex INT
          SET @StartIndex = 1
          IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character
          BEGIN
                SET @Input = @Input + @Character
          END
    
          WHILE CHARINDEX(@Character, @Input) > 0
          BEGIN
                SET @EndIndex = CHARINDEX(@Character, @Input)
    
                INSERT INTO @Output(Item)
                SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1)
    
                SET @Input = SUBSTRING(@Input, @EndIndex + 1, LEN(@Input))
          END
    
          RETURN
    END
    GO
    
    select * From STRING_SPLIT ('a,b', ',') cs 
    
    CREATE FUNCTION [dbo].[fn_SplitString]
    (@CSV VARCHAR(MAX), @Delimeter VARCHAR(100) = ',')
           RETURNS @retTable TABLE 
    (
    
        [value] VARCHAR(MAX) NULL
    )AS
    
    BEGIN
    
    DECLARE
           @vCSV VARCHAR (MAX) = @CSV,
           @vDelimeter VARCHAR (100) = @Delimeter;
    
    IF @vDelimeter = ';'
    BEGIN
        SET @vCSV = REPLACE(@vCSV, ';', '~!~#~');
        SET @vDelimeter = REPLACE(@vDelimeter, ';', '~!~#~');
    END;
    
    SET @vCSV = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@vCSV, '&', '&amp;'), '<', '&lt;'), '>', '&gt;'), '''', '&apos;'), '"', '&quot;');
    
    DECLARE @xml XML;
    
    SET @xml = '<i>' + REPLACE(@vCSV, @vDelimeter, '</i><i>') + '</i>';
    
    INSERT INTO @retTable
    SELECT
           x.i.value('.', 'varchar(max)') AS COLUMNNAME
      FROM @xml.nodes('//i')AS x(i);
    
     RETURN;
    END;
    
    
    */
    
        CREATE FUNCTION dbo.splitstring ( --CREATE OR ALTER
            @stringToSplit NVARCHAR(MAX)
        ) RETURNS @returnList TABLE ([Item] NVARCHAR (MAX))
        AS BEGIN
            DECLARE @name NVARCHAR(MAX)
            DECLARE @pos BIGINT
            SET @stringToSplit = @stringToSplit + ','             -- this should allow entries that end with a `,` to have a blank value in that "column"
            WHILE ((LEN(@stringToSplit+'_') > 1)) BEGIN           -- `+'_'` gets around LEN trimming terminal spaces. See URL referenced above
                SET @pos = COALESCE(NULLIF(CHARINDEX(',', @stringToSplit),0),LEN(@stringToSplit+'_')) -- COALESCE grabs first non-null value
                SET @name = SUBSTRING(@stringToSplit, 1, @pos-1)  --MAX size of string of type nvarchar is 4000 
                SET @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, 4000) -- With SUBSTRING fn (MS web): "If start is greater than the number of characters in the value expression, a zero-length expression is returned."
                INSERT INTO @returnList SELECT @name --additional debugging parameters below can be added
                -- + ' pos:' + CAST(@pos as nvarchar) + ' remain:''' + @stringToSplit + '''(' + CAST(LEN(@stringToSplit+'_')-1 as nvarchar) + ')'
            END
            RETURN
        END
        GO
    
    /*
    
    
    Item | L
    ---  | ---
    a    | 1
         | 0
    b    | 1
    
    Item | L   
    ---  | ---
    a    | 1
         | 0
         | 0
    
    Item | L   
    ---  | ---
    a    | 1
         | 0
         | 1
    
    Item | L   
    ---  | ---
    a    | 1
         | 0
     c   | 3
    
    CREATE FUNCTION dbo.SplitStrings
    (
       @List       NVARCHAR(MAX),
       @Delimiter  NVARCHAR(255)
    )
    RETURNS TABLE
    WITH SCHEMABINDING
    AS
       RETURN 
       (  
          SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
          FROM 
          ( 
            SELECT x = CONVERT(XML, '<i>' 
              + REPLACE(@List, @Delimiter, '</i><i>') 
              + '</i>').query('.')
          ) AS a CROSS APPLY x.nodes('i') AS y(i)
       );
    GO
    
    DECLARE @Dummy TABLE (ID INT, SomeTextToSplit NVARCHAR(MAX))
    INSERT INTO @Dummy VALUES
     (1,N'A&B;C;D;E, F')
    ,(2,N'"C" & ''D'';<C>;D;E, F');
    
    DECLARE @Delimiter NVARCHAR(10)=';'; --special effort needed (due to entities coding with "&code;")!
    
    WITH Casted AS
    (
        SELECT *
              ,CAST(N'<x>' + REPLACE((SELECT REPLACE(SomeTextToSplit,@Delimiter,N'§§Split$me$here§§') AS [*] FOR XML PATH('')),N'§§Split$me$here§§',N'</x><x>') + N'</x>' AS XML) AS SplitMe
        FROM @Dummy
    )
    SELECT Casted.ID
          ,x.value(N'.',N'nvarchar(max)') AS Part 
    FROM Casted
    CROSS APPLY SplitMe.nodes(N'/x') AS A(x)
    
    ID  Part
    1   A&B
    1   C
    1   D
    1   E, F
    2   "C" & 'D'
    2   <C>
    2   D
    2   E, F
    
    declare @T table (iden int identity, col1 varchar(100));
    insert into @T(col1) values
           ('ROOT/South America/Lima/Test/Test2')
         , ('ROOT/South America/Peru/Test/Test2')
         , ('ROOT//South America/Venuzuala ')
         , ('RtT/South America / ') 
         , ('ROOT/South Americas// '); 
    declare @split char(1) = '/';
    select @split as split;
    with cte as 
    (  select t.iden, case when SUBSTRING(REVERSE(rtrim(t.col1)), 1, 1) = @split then LTRIM(RTRIM(t.col1)) else LTRIM(RTRIM(t.col1)) + @split end  as col1, 0 as pos                             , 1 as cnt
       from @T t
       union all 
       select t.iden, t.col1                                                                                                                              , charindex(@split, t.col1, t.pos + 1), cnt + 1 
       from cte t 
       where charindex(@split, t.col1, t.pos + 1) > 0 
    )
    select t1.*, t2.pos, t2.cnt
         , ltrim(rtrim(SUBSTRING(t1.col1, t1.pos+1, t2.pos-t1.pos-1))) as bingo
    from cte t1 
    join cte t2 
      on t2.iden = t1.iden 
     and t2.cnt  = t1.cnt+1
     and t2.pos > t1.pos 
    order by t1.iden, t1.cnt;
    
    DECLARE @s VARCHAR(200) = ',1,2,,3,,,4,,,,5,'
    
    ;WITH
    a AS (SELECT i=-1, j=0 UNION ALL SELECT j, CHARINDEX(',', @s, j + 1) FROM a WHERE j > i),
    b AS (SELECT SUBSTRING(@s, i+1, IIF(j>0, j, LEN(@s)+1)-i-1) s FROM a WHERE i >= 0)
    SELECT * FROM b
    
    DECLARE @s VARCHAR(200) = '1,2333,344,4'
    
    ;WITH
    a AS (SELECT n=0, i=-1, j=0 UNION ALL SELECT n+1, j, CHARINDEX(',', @s, j+1) FROM a WHERE j > i),
    b AS (SELECT n, SUBSTRING(@s, i+1, IIF(j>0, j, LEN(@s)+1)-i-1) s FROM a WHERE i >= 0)
    SELECT * FROM b;
    
    n   s
    1   1
    2   2333
    3   344
    4   4
    
    IF EXISTS (SELECT * FROM sys.objects WHERE type = 'TF' AND name = 'TF_SplitString')
    DROP FUNCTION [dbo].[TF_SplitString]
    GO
    
    -- =============================================
    -- Author:  AviG
    -- Amendments:  Parameterize the delimeter and included the missing chars in last token - Gemunu Wickremasinghe
    -- Description: Tabel valued function that Breaks the delimeted string by given delimeter and returns a tabel having split results
    -- Usage
    -- select * from   [dbo].[TF_SplitString]('token1,token2,,,,,,,,token969',',')
    -- 969 items should be returned
    -- select * from   [dbo].[TF_SplitString]('4672978261,4672978255',',')
    -- 2 items should be returned
    -- =============================================
    CREATE FUNCTION dbo.TF_SplitString 
    ( @stringToSplit VARCHAR(MAX) ,
      @delimeter char = ','
    )
    RETURNS
     @returnList TABLE ([Name] [nvarchar] (500))
    AS
    BEGIN
    
        DECLARE @name NVARCHAR(255)
        DECLARE @pos INT
    
        WHILE LEN(@stringToSplit) > 0
        BEGIN
            SELECT @pos  = CHARINDEX(@delimeter, @stringToSplit)
    
    
            if @pos = 0
            BEGIN
                SELECT @pos = LEN(@stringToSplit)
                SELECT @name = SUBSTRING(@stringToSplit, 1, @pos)  
            END
            else 
            BEGIN
                SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)
            END
    
            INSERT INTO @returnList 
            SELECT @name
    
            SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
        END
    
     RETURN
    END
    
    declare @v nvarchar(max) = '100,201,abcde'
    
    select 
        a.value('.', 'varchar(max)')
    from
        (select cast('<M>' + REPLACE(@v, ',', '</M><M>') + '</M>' AS XML) as col) as A
        CROSS APPLY A.col.nodes ('/M') AS Split(a)
    
    DECLARE @String varchar(100) = '11,21,84,85,87'
    
    SELECT * FROM TB_PAPEL WHERE CD_PAPEL IN (SELECT value FROM STRING_SPLIT(@String, ','))
    -- EQUIVALENTE
    SELECT * FROM TB_PAPEL WHERE CD_PAPEL IN (11,21,84,85,87)