使用 CTE 以逗号分隔的字符串
comma separated string using CTE
我有一个字符串 '1,2,3,4,5,6,',我希望结果像这样的数组:
1
2
3
4
5
我已经使用函数尝试过它,也通过将它转换为 xml 来完成。
我有一个问题:
with cte1 (str1,str2) AS
(
SELECT SUBSTRING('1,2,3,4,5,6,',1,1) X,
SUBSTRING('1,2,3,4,5,6,',CHARINDEX(',','1,2,3,4,5,6,,') +1,LEN('1,2,3,4,5,6,')-2) Y
UNION all
SELECT SUBSTRING(str2,1,1) X ,SUBSTRING(str2,CHARINDEX(',',str2)+1,LEN(str2)-2) Y
FROM CTE1
WHERE SUBSTRING(str2,CHARINDEX(',',str2)+0,1) <> ' ' )
SELECT str1 FROM CTE1;
给出了预期的结果。
但如果我更改字符串,它会给出随机结果,例如:
with cte1 (str1,str2) AS
(
SELECT SUBSTRING('24,78,45,56,',1,1) X,
SUBSTRING('24,78,45,56,',CHARINDEX(',','24,78,45,56,') +1,LEN('24,78,45,56,')-2) Y
UNION all
SELECT SUBSTRING(str2,1,1) X ,SUBSTRING(str2,CHARINDEX(',',str2)+1,LEN(str2)-2) Y
FROM CTE1
WHERE SUBSTRING(str2,CHARINDEX(',',str2)+0,1) <> ' ' )
SELECT str1 FROM CTE1;
结果:
2
7
4
5
您可以使用递归 CTE
Declare @list NVARCHAR(MAX) = '1,2,3,4,5'
DECLARE @length INT = LEN(@list) + 1;
WITH a AS
(
SELECT
[start] = 1,
[end] = COALESCE(NULLIF(CHARINDEX(',',
@List, 1), 0), @length),
[value] = SUBSTRING(@list, 1,
COALESCE(NULLIF(CHARINDEX(',',
@List, 1), 0), @length) - 1)
UNION ALL
SELECT
[start] = CONVERT(INT, [end]) + 1,
[end] = COALESCE(NULLIF(CHARINDEX(',',
@list, [end] + 1), 0), @length),
[value] = SUBSTRING(@list, [end] + 1,
COALESCE(NULLIF(CHARINDEX(',',
@list, [end] + 1), 0), @length)-[end]-1)
FROM a
WHERE [end] < @length
)
SELECT [value]
FROM a
WHERE LEN([value]) > 0
OPTION (MAXRECURSION 0);
这仅在字符串类似于 '12,34,45,56....'
时有效,即字符串包含两位数字的通信分隔值
with cte1 (str1,str2) AS
(
SELECT SUBSTRING('24,78,45,56,',1,2) X,
SUBSTRING('24,78,45,56,',CHARINDEX(',','24,78,45,56,') +1,LEN('24,78,45,56,')-2) Y
UNION all
SELECT SUBSTRING(str2,1,2) X ,SUBSTRING(str2,CHARINDEX(',',str2)+1,LEN(str2)-2) Y
FROM CTE1
WHERE SUBSTRING(str2,CHARINDEX(',',str2)+0,2) <> ' ' )
SELECT str1 FROM CTE1;
您应该通过在用户定义函数上创建接受逗号分隔字符串并为此字符串提供 table 值的通用解决方案
像这样的函数定义
CREATE FUNCTION SplitItem( @ItemIDs VARCHAR(MAX))
RETURNS @ItemTable TABLE ( Item VARCHAR(200) )
AS
BEGIN
DECLARE @Item VARCHAR(200)
DECLARE @Index INT
WHILE LEN(@ItemIDs) <> 0
BEGIN
SET @Index = PATINDEX('%,%', @ItemIDs)
IF @Index > 0
BEGIN
SET @Item = SUBSTRING(@ItemIDs, 1, @Index - 1)
SET @ItemIDs = RIGHT(@ItemIDs, LEN(@ItemIDs) - @Index)
INSERT INTO @ItemTable
VALUES ( @Item )
END
ELSE
BEGIN
BREAK
END
END
SET @Item = @ItemIDs
INSERT INTO @ItemTable
VALUES ( @Item )
RETURN
END
并像这样使用这个函数
SELECT Item
FROM SplitItem('1,2,3,44,55,66,77')
这将给出这样的输出
1
2
3
44
55
66
77
你可以这样做:
DECLARE @string NVARCHAR(MAX) = '1,2,3,4,5,6,',
@xml xml
select @xml = cast('<d><q>'+REPLACE(@string,',','</q><q>')+'</q></d>' as xml)
SELECT n.v.value('.','nvarchar(2)')
FROM @xml.nodes('/d/q') AS n(v);
结果:
----
1
2
3
4
5
6
(7 row(s) affected)
我有一个字符串 '1,2,3,4,5,6,',我希望结果像这样的数组:
1
2
3
4
5
我已经使用函数尝试过它,也通过将它转换为 xml 来完成。
我有一个问题:
with cte1 (str1,str2) AS
(
SELECT SUBSTRING('1,2,3,4,5,6,',1,1) X,
SUBSTRING('1,2,3,4,5,6,',CHARINDEX(',','1,2,3,4,5,6,,') +1,LEN('1,2,3,4,5,6,')-2) Y
UNION all
SELECT SUBSTRING(str2,1,1) X ,SUBSTRING(str2,CHARINDEX(',',str2)+1,LEN(str2)-2) Y
FROM CTE1
WHERE SUBSTRING(str2,CHARINDEX(',',str2)+0,1) <> ' ' )
SELECT str1 FROM CTE1;
给出了预期的结果。 但如果我更改字符串,它会给出随机结果,例如:
with cte1 (str1,str2) AS
(
SELECT SUBSTRING('24,78,45,56,',1,1) X,
SUBSTRING('24,78,45,56,',CHARINDEX(',','24,78,45,56,') +1,LEN('24,78,45,56,')-2) Y
UNION all
SELECT SUBSTRING(str2,1,1) X ,SUBSTRING(str2,CHARINDEX(',',str2)+1,LEN(str2)-2) Y
FROM CTE1
WHERE SUBSTRING(str2,CHARINDEX(',',str2)+0,1) <> ' ' )
SELECT str1 FROM CTE1;
结果:
2
7
4
5
您可以使用递归 CTE
Declare @list NVARCHAR(MAX) = '1,2,3,4,5'
DECLARE @length INT = LEN(@list) + 1;
WITH a AS
(
SELECT
[start] = 1,
[end] = COALESCE(NULLIF(CHARINDEX(',',
@List, 1), 0), @length),
[value] = SUBSTRING(@list, 1,
COALESCE(NULLIF(CHARINDEX(',',
@List, 1), 0), @length) - 1)
UNION ALL
SELECT
[start] = CONVERT(INT, [end]) + 1,
[end] = COALESCE(NULLIF(CHARINDEX(',',
@list, [end] + 1), 0), @length),
[value] = SUBSTRING(@list, [end] + 1,
COALESCE(NULLIF(CHARINDEX(',',
@list, [end] + 1), 0), @length)-[end]-1)
FROM a
WHERE [end] < @length
)
SELECT [value]
FROM a
WHERE LEN([value]) > 0
OPTION (MAXRECURSION 0);
这仅在字符串类似于 '12,34,45,56....'
时有效,即字符串包含两位数字的通信分隔值
with cte1 (str1,str2) AS
(
SELECT SUBSTRING('24,78,45,56,',1,2) X,
SUBSTRING('24,78,45,56,',CHARINDEX(',','24,78,45,56,') +1,LEN('24,78,45,56,')-2) Y
UNION all
SELECT SUBSTRING(str2,1,2) X ,SUBSTRING(str2,CHARINDEX(',',str2)+1,LEN(str2)-2) Y
FROM CTE1
WHERE SUBSTRING(str2,CHARINDEX(',',str2)+0,2) <> ' ' )
SELECT str1 FROM CTE1;
您应该通过在用户定义函数上创建接受逗号分隔字符串并为此字符串提供 table 值的通用解决方案
像这样的函数定义
CREATE FUNCTION SplitItem( @ItemIDs VARCHAR(MAX))
RETURNS @ItemTable TABLE ( Item VARCHAR(200) )
AS
BEGIN
DECLARE @Item VARCHAR(200)
DECLARE @Index INT
WHILE LEN(@ItemIDs) <> 0
BEGIN
SET @Index = PATINDEX('%,%', @ItemIDs)
IF @Index > 0
BEGIN
SET @Item = SUBSTRING(@ItemIDs, 1, @Index - 1)
SET @ItemIDs = RIGHT(@ItemIDs, LEN(@ItemIDs) - @Index)
INSERT INTO @ItemTable
VALUES ( @Item )
END
ELSE
BEGIN
BREAK
END
END
SET @Item = @ItemIDs
INSERT INTO @ItemTable
VALUES ( @Item )
RETURN
END
并像这样使用这个函数
SELECT Item
FROM SplitItem('1,2,3,44,55,66,77')
这将给出这样的输出
1
2
3
44
55
66
77
你可以这样做:
DECLARE @string NVARCHAR(MAX) = '1,2,3,4,5,6,',
@xml xml
select @xml = cast('<d><q>'+REPLACE(@string,',','</q><q>')+'</q></d>' as xml)
SELECT n.v.value('.','nvarchar(2)')
FROM @xml.nodes('/d/q') AS n(v);
结果:
----
1
2
3
4
5
6
(7 row(s) affected)