FOR XML路径出现问题-无法串联

时间:2019-01-16 19:13:53

标签: sql xml sql-server-2016

我遇到一种情况,一个订单可以包含多个购买的许可证-如果该订单确实包含多个许可证,我想在单个单元格中显示许可证说明,其值用逗号分隔。如果我们使用的是SQL 2017,则可以使用STRING_AGG,但如果使用的是SQL 2016,那么我将尝试使用经过验证的STUFF / FOR XML Path方法。

在下面的屏幕截图中,客户4340073购买了两个许可证,订单号为18519173: enter image description here

将STUFF / FOR XML路径添加到T-SQL时,无法获得在同一记录中显示许可证说明的预期结果-每个许可证仍具有自己的行。

SELECT   x.CustomerID ,
         x.ATOLicenseTypeID ,
         x.ATOLicense ,
         x.AuthorizationBeginDate ,
         x.AuthorizationEndDate ,
         x.OrderID ,
         x.OrderDate ,
         STUFF ( (
                 SELECT ',' + lt.description
                 FROM   dbo.LicenseTypes AS lt
                 --INNER JOIN #XMLPATH ON lt.id = x.OrderLicenseTypeID
                 WHERE  lt.id = x.OrderLicenseTypeID
                 --GROUP BY ',' + lt.description
                 FOR XML PATH ( '' )
             ) , 1 , 1 , '' ) AS Licenses
FROM     #XMLPATH AS x
--GROUP BY x.CustomerID ,
--         x.ATOLicenseTypeID ,
--         x.ATOLicense ,
--         x.AuthorizationBeginDate ,
--         x.AuthorizationEndDate ,
--         x.OrderID ,
--         x.OrderDate ,
--         x.OrderLicenseTypeID;

enter image description here

我尝试了不同的方式将子查询加入外部查询,并添加和删除了GROUP BY以实现所需的结果,但是对我来说没有任何作用。

关于此查询出现问题的任何建议?

样本数据集:

DROP TABLE IF EXISTS #XMLPATH;

CREATE TABLE #XMLPATH
    (
        CustomerID INT ,
        ATOLicenseTypeID INT ,
        ATOLicense VARCHAR (500) ,
        AuthorizationBeginDate DATE ,
        AuthorizationEndDate DATE ,
        OrderID INT ,
        OrderDate DATETIME ,
        OrderLicenseTypeID INT
    );
INSERT INTO #XMLPATH
VALUES ( 4341073, 52, 'Temporary Resident Fishing', N'2019-01-07T00:00:00', N'2019-01-07T00:00:00', 18519136, N'2019-01-07T12:01:55.317', 2141 ) ,
       ( 4341073, 52, 'Temporary Resident Fishing', N'2019-01-07T00:00:00', N'2019-01-07T00:00:00', 18519173, N'2019-01-07T12:34:13.107', 204 ) ,
       ( 4341073, 52, 'Temporary Resident Fishing', N'2019-01-07T00:00:00', N'2019-01-07T00:00:00', 18519173, N'2019-01-07T12:34:13.107', 2141 );

SELECT * FROM #XMLPATH;

SELECT   x.CustomerID ,
         x.ATOLicenseTypeID ,
         x.ATOLicense ,
         x.AuthorizationBeginDate ,
         x.AuthorizationEndDate ,
         x.OrderID ,
         x.OrderDate ,
         STUFF ( (
                 SELECT ',' + lt.description
                 FROM   dbo.LicenseTypes AS lt
                 --INNER JOIN #XMLPATH ON lt.id = x.OrderLicenseTypeID
                 WHERE  lt.id = x.OrderLicenseTypeID
                 --GROUP BY ',' + lt.description
                 FOR XML PATH ( '' )
             ) , 1 , 1 , '' ) AS Licenses
FROM     #XMLPATH AS x
GROUP BY x.CustomerID ,
         x.ATOLicenseTypeID ,
         x.ATOLicense ,
         x.AuthorizationBeginDate ,
         x.AuthorizationEndDate ,
         x.OrderID ,
         x.OrderDate ,
         x.OrderLicenseTypeID;

1 个答案:

答案 0 :(得分:1)

为了将一个OrderID的所有行作为一个结果行,您不得在OrderLicenseTypeID中包括分隔信息(GROUP BY)。但是然后您遇到了一个问题:您无法在FOR XML构造中使用此ID。

诀窍是(如您未作评论的试验所示),将源表添加到子选择并在其中使用分组列进行过滤。但是您必须使用不同的别名将它们作为两个不同的集合来处理。试试这个:

(我必须再添加一个临时表来对此进行测试...)

SELECT   x.CustomerID ,
         x.ATOLicenseTypeID ,
         x.ATOLicense ,
         x.AuthorizationBeginDate ,
         x.AuthorizationEndDate ,
         x.OrderID ,
         x.OrderDate ,
         STUFF ( (
                 SELECT ',' + lt.description
                 FROM   #XMLPATH x2 
                 INNER JOIN #LicenseTypes AS lt ON lt.id=x2.OrderLicenseTypeID
                 WHERE  x2.OrderID = x.OrderID --you might need to add more columns here....
                 --in most cases we want to add an ORDER BY
                 FOR XML PATH ( '' )
             ) , 1 , 1 , '' ) AS Licenses
FROM     #XMLPATH AS x
GROUP BY x.CustomerID ,
         x.ATOLicenseTypeID ,
         x.ATOLicense ,
         x.AuthorizationBeginDate ,
         x.AuthorizationEndDate ,
         x.OrderID ,
         x.OrderDate;

顺便说一句:从v2017开始,有STRING_AGG(),这使事情变得更加容易...