我遇到一种情况,一个订单可以包含多个购买的许可证-如果该订单确实包含多个许可证,我想在单个单元格中显示许可证说明,其值用逗号分隔。如果我们使用的是SQL 2017,则可以使用STRING_AGG,但如果使用的是SQL 2016,那么我将尝试使用经过验证的STUFF / FOR XML Path方法。
在下面的屏幕截图中,客户4340073购买了两个许可证,订单号为18519173:
将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;
我尝试了不同的方式将子查询加入外部查询,并添加和删除了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;
答案 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(),这使事情变得更加容易...