【问题标题】:Issue converting SQL column to CSV via XML通过 XML 将 SQL 列转换为 CSV 的问题
【发布时间】:2019-01-08 20:21:33
【问题描述】:

我将 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 Server 2017。此版本是否不支持以前版本的 XML-to-CSV hack?

【问题讨论】:

  • 您似乎想使用WHERE r.Report_ID = rr.Report_ID 而不是WHERE r.Role_ID = rr.Role_ID,但由于您不会共享 DDL,我们怎么知道?
  • 原始数据将帮助我们理解这里。我们看不到你所看到的。
  • 表被规范化,连接表是一个简单的多对多 ID 映射。 Role 没有 Report_ID,Report 也没有 Role_ID。 @Paurian 的回答解决了这个问题。

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


【解决方案1】:

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

这个版本不支持以前版本的 XML-to-CSV hack 吗?

是的,确实如此(正如 Paurian 的回答告诉你的那样),但更好:This version supports STRING_AGG():

不知道你的表我设置了一个mini mockup来模拟你的问题(根据你的表是规范化的,连接表是一个简单的多对多ID映射):

两个表之间有一个m:n-mapping 表

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

【讨论】:

  • 谢谢,我不知道这个。这是一个简单得多的语法,感觉不那么“hacky”。我使用 CTE 将聚合列连接到非聚合列,它的工作原理就像一个冠军。据我所知,这比 XML 版本的性能还要好。
【解决方案2】:

有一个名为“ReportRole”的表表示您的案例中报告和角色之间的链接表。如果是这样,您可以将 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;

【讨论】:

    猜你喜欢
    • 2021-02-17
    • 2014-07-20
    • 1970-01-01
    • 2017-04-28
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 2014-08-13
    • 2021-11-21
    相关资源
    最近更新 更多