通过XML将SQL列转换为CSV的问题

时间:2019-01-08 20:21:34

标签: sql-server tsql sql-server-2017

我将SQL Server报表应用程序中的逗号分隔字段替换为多对多关系。尚无法替换应用程序代码,因此我需要派生当前期望的同一CSV列。过去我曾经使用过FOR XML PATH技巧,它似乎是一种基于集的快速解决方案,应该易于实现。

我当前的查询如下:

SELECT   
    Report = rr.Report_ID, 
    RoleList = STUFF((SELECT   ', ' + r.[Name] AS [text()] 
                      FROM [dbo].[Role] r 
                      WHERE r.Role_ID = rr.Role_ID
                      FOR XML PATH ('')), 1, 1, '') 
FROM     
    [dbo].ReportRole rr
ORDER BY 
    rr.Report_ID;

我期望的是:

Report   RoleList
--------------------------------------------------------------------
  2      Senior Application Developer
  3      Senior Application Developer, Manager Information Systems

但是我得到的却是这样:

Report   RoleList
--------------------------------------
  2      Senior Application Developer
  3      Senior Application Developer
  3      Manager Information Systems

我正在使用SQL Server2017。此版本不支持以前版本的XML-to-CSV hack?

2 个答案:

答案 0 :(得分:0)

具有一个名为“ ReportRole”的表表示在您的案例中Report与Role之间的链接表。如果是这样,则可以将ReportRole表作为内部查询的一部分,并将报告ID保留在外部查询中:

SELECT   
    Report = rpt.Report_ID, 
    RoleList = STUFF((SELECT   ', ' + r.[Name] AS [text()] 
                      FROM [dbo].[Role] r
                           JOIN [dbo].ReportRole rr
                             ON r.Role_ID = rr.Role_ID
                      WHERE rr.Report_ID = rpt.Report_ID
                      FOR XML PATH ('')), 1, 1, '') 
FROM     
    [dbo].Report rpt
ORDER BY 
    rpt.Report_ID;

答案 1 :(得分:0)

您已经用 SQL-Server 2017 标记了问题,然后问:

  

此版本不支持以前版本中的XML-to-CSV黑客吗?

是的,确实可以做到(正如Paurian的回答告诉你的那样),但效果更好:This version supports STRING_AGG()

不知道您的表我设置了一个迷你模型来模拟您的问题(根据您的表已规范化,联接表是简单的多对多ID映射< / em>):

两个表之间有一个m:n映射表

DECLARE @mockupA TABLE(ID INT,SomeValue VARCHAR(10));
INSERT INTO @mockupA VALUES(1,'A1'),(2,'A2');

DECLARE @mockupB TABLE(ID INT,SomeValue VARCHAR(10));
INSERT INTO @mockupB VALUES(1,'B1'),(2,'B2');

DECLARE @mockupMapping TABLE(ID_A INT,ID_B INT);
INSERT INTO @mockupMapping VALUES(1,1),(1,2),(2,2);

-查询将简单地连接这些表,然后将GROUP BYSTRING_AGG()一起使用。 WITHIN GROUP子句允许您确定串联字符串的排序顺序。

SELECT a.ID,a.SomeValue
      ,STRING_AGG(b.SomeValue,', ') WITHIN GROUP(ORDER BY b.ID) AS B_Values
FROM @mockupA a
INNER JOIN @mockupMapping m ON a.ID=m.ID_A
INNER JOIN @mockupB b ON b.ID=m.ID_B
GROUP BY a.ID,a.SomeValue;

结果

ID  SomeValue   B_Values
1   A1          B1, B2
2   A2          B2