在SQL Server中使用逗号分割字符串

时间:2015-05-13 06:59:59

标签: sql-server sql-server-2008 tsql sql-server-2012

请帮助如何用逗号分隔字符串中的单词

例如:'abcdef'

输出:'a,b,c,d,e,f'

7 个答案:

答案 0 :(得分:5)

如果你想操作tsql变量:

DECLARE @str VARCHAR(40) = 'abcdef'

您可以使用以下代码使用spt_values创建一个标记,并在字符串中STUFF注入,字符:

SELECT @str = STUFF(@str, Number * 2, 0, ',')
FROM [master].[dbo].[spt_values]
WHERE Type = 'P' AND
      Number BETWEEN 1 AND LEN(@str) - 1

执行上述操作后,@stra,b,c,d,e,f

答案 1 :(得分:3)

这在纯SQL中并不是最好的处理,并且更适合应用程序层或CLR,但一种解决方案是将字符串拆分为单独的组件,然后使用逗号分隔符重建它。要首先执行此操作,您需要一个数字表,以下系列深入探讨了执行此操作的最佳方法:

为了答案,我假设您没有数字表,需要动态创建一个,最有效的方法是使用堆叠CTE。以下将返回从1到10000的列表:

WITH N1 AS (SELECT N FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (Number) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) FROM N3)
SELECT  *
FROM    Numbers;

然后您可以使用这些数字来分割字符串:

DECLARE @T TABLE (Col VARCHAR(10));
INSERT @T VALUES ('abcdef');

WITH N1 AS (SELECT N FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (Number) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) FROM N3)

SELECT  *,
        Letter = SUBSTRING(t.Col, n.Number, 1)
FROM    @T AS t
        INNER JOIN Numbers n
            ON n.Number <= LEN(t.Col);

这会给你:

Col     Number  Letter
------------------------
abcdef  1       a
abcdef  2       b
abcdef  3       c
abcdef  4       d
abcdef  5       e
abcdef  6       f

然后,您可以使用SQL Servers XML extensions重建字符串:

DECLARE @T TABLE (Col VARCHAR(10));
INSERT @T VALUES ('abcdef'), ('test');

WITH N1 AS (SELECT N FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (Number) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) FROM N3)

SELECT  t.Col,
        Split = (   SELECT  CASE WHEN n.Number = 1 THEN '' ELSE ',' END + SUBSTRING(t2.Col, n.Number, 1)
                    FROM    @T AS t2
                            INNER JOIN Numbers n
                                ON n.Number <= LEN(t2.Col)
                    WHERE   t2.Col = t.Col
                    FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)')
FROM    @T AS t;

此方法的好处是您可以将其用作内联表值函数:

CREATE FUNCTION dbo.InjectDelimiter (@String VARCHAR(1000), @Delimiter CHAR(1))
RETURNS TABLE 
AS
RETURN 
(   WITH N1 AS (SELECT N FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
    N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
    N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
    Numbers (Number) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) FROM N3)
    SELECT  Split = (   SELECT  CASE WHEN n.Number = 1 THEN '' ELSE @Delimiter END + SUBSTRING(@String, n.Number, 1)
                        FROM    Numbers n
                        WHERE   n.Number <= LEN(@String)
                        FOR XML PATH(''), TYPE
                    ).value('.', 'NVARCHAR(MAX)')
);

然后你可以把它称为:

SELECT  t.Name, i.Split
FROM    sys.tables AS t
        CROSS APPLY dbo.InjectDelimiter(t.name, ',') AS i;

如果你需要在多行上调用它,那么它的性能会比标量函数好得多。

答案 2 :(得分:1)

我会使用while循环:

DECLARE @str VARCHAR(max) = 'abcdef'

DECLARE @loop INT = LEN(@str)

WHILE @loop > 1
  SELECT @str = STUFF(@str, @loop, 0, ','), @loop -= 1

SELECT @str

答案 3 :(得分:0)

您可以为此

创建以下功能
CREATE FUNCTION PutCommasBetweenChars 

   (@String VARCHAR(100))

RETURNS VARCHAR(100)
AS
BEGIN
   DECLARE @pos INT, @result VARCHAR(100); 
   SET @result = @String; 
   SET @pos = 2 -- location where we want first space 
   WHILE @pos < LEN(@result)+1 
   BEGIN 
       SET @result = STUFF(@result, @pos, 0, ','); 
       SET @pos = @pos+2; 
   END 
   RETURN @result; 
END
GO

按以下步骤执行

print dbo.PutCommasBetweenChars('abcdef')

答案 4 :(得分:0)

前一段时间我想出了这个解决方案:

Declare @separator as nvarchar(1)= ',' Declare @filterlist as nvarchar(MAX) = '1,2,3,4,5' IF OBJECT_ID('tempdb..#filterList') IS NOT NULL DROP TABLE #filterlist --Create temporary filter list table create table #FilterList ( filter varchar(100) Not NULL ) --Add 1 comma to the filter list, used for processing the list set @filterlist = @filterList + @separator --Declare and set default variable values for processing Filter list DECLARE @pos INT DECLARE @len INT DECLARE @value varchar(100) set @pos = 0 set @len = 0 --Loop thru the string of filter list, separate the , values and insert into the #Filterlist WHILE CHARINDEX(@separator , @filterList, @pos+1)>0 BEGIN set @len = CHARINDEX(@separator , @filterList, @pos+1) - @pos set @value = SUBSTRING(@filterList, @pos, @len) insert Into #FilterList (filter) Values(@value) set @pos = CHARINDEX(@separator , @filterList, @pos+@len) + 1 END select * from #FilterList

答案 5 :(得分:0)

花了一些时间后我找到了你的解决方案

DECLARE @Chars VARCHAR(8000) 

SELECT  @Chars = COALESCE(@Names + ', ', '') + Main.SplitChar
FROM 
(

select (substring(a.b, v.number+1, 1)) AS SplitChar
from (select 'QWERTY' b) a
join master..spt_values v on v.number < len(a.b)
where v.type = 'P'
) AS MaIn

SELECT @Chars

请告诉我,是否有效。 :)

答案 6 :(得分:0)

Thank you all ! I tried below code, but I got better answers from you all guys

CREATE TABLE #TEMP (ID INT IDENTITY, CHARR VARCHAR(MAX))
DECLARE @DATA NVARCHAR(MAX)='ABCDEFG'

DECLARE @LEN INT = LEN(@DATA)
DECLARE @INT INT = 1
WHILE @INT<=@LEN
BEGIN 
INSERT INTO #TEMP VALUES (SUBSTRING(@DATA,@INT,1))
SET @INT=@INT+1
end

SELECT STUFF(
(SELECT ',' + S.CHARR
FROM #TEMP s
ORDER BY s.ID
FOR XML PATH('')),1,1,'') AS CSV