Having Trouble with FOR XML Path - No Concatenating

问题: I have a situation where an order can contain multiple license purchases - and if the order does contain multiple licenses, I want to display the license descriptions in a...

问题:

I have a situation where an order can contain multiple license purchases - and if the order does contain multiple licenses, I want to display the license descriptions in a single cell with the values separated by commas. If we were on SQL 2017, I could use STRING_AGG but we are on SQL 2016 so I am trying the tried and true STUFF / FOR XML Path method.

From the screenshot below, Customer 4341073 had two license purchases on Order ID 18519173: enter image description here

When I add the STUFF / FOR XML Path to the T-SQL, I am not able to achieve the desired result of showing the license description in the same record - each license still has it's own row.

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

I've tried different ways to join the sub-query to the outer query and added and removed GROUP BY to achieve the desired result but nothing is working for me.

Any suggestions on where I am going wrong with this query?

Sample dataset:

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:

In order to get all rows of one OrderID as one result-row, you must not include the separating information (the OrderLicenseTypeID) into the GROUP BY. But then you have the issue you've encountered: You cannot use this ID within your FOR XML construct.

The trick is (as your out-commented trials show), to add the source table to the sub-select and filter there with a grouped column. But you have to use different aliases to deal with them as two different sets. Try this:

(I had to add one more temp table to test this...)

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;

Btw: Starting with v2017 there is STRING_AGG(), which makes this much easier...

  • 发表于 2019-01-22 00:26
  • 阅读 ( 206 )
  • 分类:网络文章

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除