Sql server 跨行拆分单行

Sql server 跨行拆分单行,sql-server,tsql,split,Sql Server,Tsql,Split,给定一个包含行和数据的升级表,例如: PromotionId Codes 1 a,b 2 c 3 d,e,f 我如何编写一个查询来返回它,如下所示: PromotionId Codes 1 a 1 b 2 c 3 d 3 e 3 f 基本上,我希望将

给定一个包含行和数据的升级表,例如:

PromotionId    Codes
1              a,b
2              c
3              d,e,f
我如何编写一个查询来返回它,如下所示:

PromotionId    Codes
1              a
1              b
2              c
3              d
3              e
3              f
基本上,我希望将代码拆分为多行。

您可以使用拆分表值函数,例如:

CREATE FUNCTION [dbo].[Split]
(
    @ItemList NVARCHAR(MAX), 
    @delimiter CHAR(1)
)
RETURNS @IDTable TABLE (Item VARCHAR(50))  
AS      

BEGIN    
    DECLARE @tempItemList NVARCHAR(MAX)
    SET @tempItemList = @ItemList

    DECLARE @i INT    
    DECLARE @Item NVARCHAR(4000)

    SET @tempItemList = REPLACE (@tempItemList, ' ', '')
    SET @i = CHARINDEX(@delimiter, @tempItemList)

    WHILE (LEN(@tempItemList) > 0)
    BEGIN
        IF @i = 0
            SET @Item = @tempItemList
        ELSE
            SET @Item = LEFT(@tempItemList, @i - 1)
        INSERT INTO @IDTable(Item) VALUES(@Item)
        IF @i = 0
            SET @tempItemList = ''
        ELSE
            SET @tempItemList = RIGHT(@tempItemList, LEN(@tempItemList) - @i)
        SET @i = CHARINDEX(@delimiter, @tempItemList)
    END 
    RETURN
END  
然后,您可以使用加入它:

SELECT PromotionId, CodeList.Item AS Codes
FROM Promotion p
    CROSS APPLY dbo.Split(Codes, ',') CodeList
编辑:这里是对你的数据的修改:

结果:

PROMOTIONID    CODES
  1             a
  1             b
  2             c
  3             d
  3             e
  3             f

我相信在T-SQL中分割/联系事物最快的方法是使用XML。以下是我使用的解决方案:

;WITH CTE(PromotionID,Codes)
AS
(
    SELECT  PromotionID
           ,CAST(N'<r><![CDATA[' + REPLACE(Codes, ',', ']]></r><r><![CDATA[') + ']]></r>' AS XML) AS Codes
    FROM @SourceTable
)
SELECT  PromotionID
       ,Code
FROM CTE
CROSS APPLY (SELECT DISTINCT RTRIM(LTRIM(Tbl.Col.value('.', 'nvarchar(250)'))) AS Code FROM Codes.nodes('//r') Tbl(Col)) AS List
我使用了公共表表达式将代码转换为XML。然后,我使用一种常见的方法将XML拆分为各个元素。以下是完整的工作示例:

SET NOCOUNT ON
GO

DECLARE @SourceTable TABLE
(
    PromotionID INT,
    Codes NVARCHAR(20)
)

INSERT INTO @SourceTable (PromotionID,Codes)
VALUES   (1,'a,b')
        ,(2,'c')
        ,(3,'d,e,f')

;WITH CTE(PromotionID,Codes)
AS
(
    SELECT  PromotionID
           ,CAST(N'<r><![CDATA[' + REPLACE(Codes, ',', ']]></r><r><![CDATA[') + ']]></r>' AS XML) AS Codes
    FROM @SourceTable
)
SELECT  PromotionID
       ,Code
FROM CTE
CROSS APPLY (SELECT DISTINCT RTRIM(LTRIM(Tbl.Col.value('.', 'nvarchar(250)'))) AS Code FROM Codes.nodes('//r') Tbl(Col)) AS List


SET NOCOUNT OFF
GO

如何将SQL与XML一起使用,如下所示:

declare @X xml

SET @X= (SELECT CONVERT(xml,'<s id="'+cast(PromotionId as varchar)+'">' + REPLACE(Codes,',','</s><s id="'+cast(PromotionId as varchar)+'">') + '</s>') FROM t1
FOR XML RAW)

SELECT c.value('(@id)[1]','int') as PromotionId, c.value('.','varchar(50)') as Code
FROM @X.nodes('/row/s') T(c)
它将更高效、更快


拆分的优点是,您经常需要这样一个函数,除此之外,它还取决于哪个函数更快。这表明拆分更有效,至少有时是这样:拆分功能,如红线所示,缩放得很漂亮,而且很难测量,速度很快。相比之下,使用基于元素的列表的XML eShred技术和这种XQuery语法显示出可怕的伸缩性。我也有很多使用XML的类型拆分函数。您的split函数非常慢,因为,首先它使用循环,其次它使用字符串运算符。众所周知,字符串的速度有多慢,特别是SQL Server处理的大字符串。因此,使用XML更快,而且只需要几行代码。我没有对这两种方法进行测量,我也不认为我的方法有更多的行或难以理解:选择PromotionId,CodeList.Item作为升级中的代码交叉应用dbo.SplitCode,,,'CodeList。但是,通常在导入等情况下需要这样的函数。当您可以将其存储为单独的记录时,使用逗号或任何分隔字符串作为输入或将其存储在数据库中是不正常的。无论分隔符是“,”或“|”还是其他任何东西,函数都可以轻松处理这一点。无论如何,我同意您的看法,在大多数情况下,但并非所有情况下,在导入数据时都会使用此选项。