解析逗号分隔的列并转换为行

时间:2018-01-08 19:28:08

标签: tsql sql-server-2008-r2

假设我有一个这样的表,在一列中有一个未确定的逗号分隔值:

thingID    personID

1          123,234,345

2          456,567

我想把它变成这样的形式:

thingID    personID

1          123

1          234

1          345

2          456

2          567

这样做的最佳选择是什么? 哦,我应该提一下数据是在SQL 2008 R2数据库中,所以我可能无法使用最新的功能。

2 个答案:

答案 0 :(得分:0)

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

现在我们有了一个字符串拆分功能,创建并填充样本表(在将来的问题中保存这一步骤):

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

You can see a live demo on rextester.

答案 1 :(得分:0)

有几种方法可以做到这一点。以下是SQL Server 2008的两种方法:

XML-Method:要求字符串允许xml-trick(没有无效的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