解析以逗号分隔的列并转置为行
Parsing a comma delimited column and transposing into rows
假设我有一个像这样的 table,其中一列中有不确定数量的逗号分隔值:
thingID personID
1 123,234,345
2 456,567
我想把它变成这样的形式:
thingID personID
1 123
1 234
1 345
2 456
2 567
我这样做的最佳选择是什么?
哦,我应该提到数据在 SQL 2008 R2 数据库中,所以我可能无法使用最新的功能。
使用 CROSS APPLY
和字符串拆分功能。
要找到最适合您的字符串拆分函数,请阅读 Aaron Bertrand 的 Split strings the right way – or the next best way.
对于这个演示,我选择使用 SplitStrings_XML
函数,因为它是文章中的第一个纯 t-sql 函数:
CREATE FUNCTION dbo.SplitStrings_XML
(
@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
现在我们有了一个字符串拆分函数,创建并填充示例 table(请 在您以后的问题中省去这一步):
DECLARE @T AS TABLE
(
thingID int,
personID varchar(max)
)
INSERT INTO @T VALUES
(1, '123,234,345'),
(2, '456,567')
查询:
SELECT thingId, Item
FROM @T
CROSS APPLY dbo.SplitStrings_XML(personID, ',')
结果:
thingId Item
1 123
1 234
1 345
2 456
2 567
有几种方法可以做到这一点。以下是 SQL Server 2008 的两种方法:
XML-方法: 要求字符串允许 xml-技巧(没有无效的 XML 字符)
SELECT a.thingID, Split.a.value('.', 'VARCHAR(100)') AS Data
FROM (SELECT OtherID,
CAST('<M>' + REPLACE(personID, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM table1) AS A CROSS APPLY Data.nodes ('/M') AS Split(a);
递归方法:
;WITH tmp(thingID, DataItem, Data) AS (
SELECT thingID, LEFT(personID, CHARINDEX(',', personID + ',') - 1),
STUFF(personID, 1, CHARINDEX(',', personID + ','), '')
FROM table1
UNION ALL
SELECT thingID, LEFT(personID, CHARINDEX(',', personID + ',') - 1),
STUFF(personID, 1, CHARINDEX(',', personID + ','), '')
FROM tmp
WHERE Data > ''
)
SELECT thingID, DataItem AS personID
FROM tmp
假设我有一个像这样的 table,其中一列中有不确定数量的逗号分隔值:
thingID personID
1 123,234,345
2 456,567
我想把它变成这样的形式:
thingID personID
1 123
1 234
1 345
2 456
2 567
我这样做的最佳选择是什么? 哦,我应该提到数据在 SQL 2008 R2 数据库中,所以我可能无法使用最新的功能。
使用 CROSS APPLY
和字符串拆分功能。
要找到最适合您的字符串拆分函数,请阅读 Aaron Bertrand 的 Split strings the right way – or the next best way.
对于这个演示,我选择使用 SplitStrings_XML
函数,因为它是文章中的第一个纯 t-sql 函数:
CREATE FUNCTION dbo.SplitStrings_XML
(
@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
现在我们有了一个字符串拆分函数,创建并填充示例 table(请 在您以后的问题中省去这一步):
DECLARE @T AS TABLE
(
thingID int,
personID varchar(max)
)
INSERT INTO @T VALUES
(1, '123,234,345'),
(2, '456,567')
查询:
SELECT thingId, Item
FROM @T
CROSS APPLY dbo.SplitStrings_XML(personID, ',')
结果:
thingId Item
1 123
1 234
1 345
2 456
2 567
有几种方法可以做到这一点。以下是 SQL Server 2008 的两种方法:
XML-方法: 要求字符串允许 xml-技巧(没有无效的 XML 字符)
SELECT a.thingID, Split.a.value('.', 'VARCHAR(100)') AS Data
FROM (SELECT OtherID,
CAST('<M>' + REPLACE(personID, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM table1) AS A CROSS APPLY Data.nodes ('/M') AS Split(a);
递归方法:
;WITH tmp(thingID, DataItem, Data) AS (
SELECT thingID, LEFT(personID, CHARINDEX(',', personID + ',') - 1),
STUFF(personID, 1, CHARINDEX(',', personID + ','), '')
FROM table1
UNION ALL
SELECT thingID, LEFT(personID, CHARINDEX(',', personID + ',') - 1),
STUFF(personID, 1, CHARINDEX(',', personID + ','), '')
FROM tmp
WHERE Data > ''
)
SELECT thingID, DataItem AS personID
FROM tmp