【问题标题】:Summarize the list into a comma-separated string将列表汇总为逗号分隔的字符串
【发布时间】:2012-03-21 19:31:15
【问题描述】:

这是可以每天更改的当前结果

    (int)   (nvarchar)
    Number   Grade
    --------------
         1       a
         1       c
         2       a
         2       b
         2       c
         3       b
         3       a

我需要帮助是在下面实现这个结果。

Number      Grade
-----------------
     1       a, c
     2    a, b, c
     3       b, a

【问题讨论】:

标签: sql sql-server tsql xpath


【解决方案1】:

用途:

declare @t table(Number int, Grade varchar)

insert @t values(1, 'a'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c'),
(3, 'b'), (3, 'a')

select t1.Number
    , stuff((
        select ',' + Grade
        from @t t2
        where t2.Number = t1.Number
        for xml path(''), type
    ).value('.', 'varchar(max)'), 1, 1, '') [values]
from @t t1
group by t1.Number

【讨论】:

  • 我在哪里可以阅读更多关于 ").value('.', 'varchar(max)')" 和 "[values]" 以了解更多这些语法的信息?
  • @FullmetalBoy – 子查询创建 XML 并且 value 用于获取 XML 的值。阅读更多关于价值here的信息。
  • 还有一些我不明白的问题。 Q1 = 为什么使用以及如何使用“。”来自“值('.'”?
  • @DWD,你是什么意思? . 是选择 XML 上下文节点的 XPath 表达式:w3.org/TR/xpath/#path-abbrev
  • 我相信您可以放弃 TYPE 和随后的 .value() 调用。 TYPE 指令将输出转换为 XML,然后要求您使用 .value() 提取所需的值。没有它,您可以直接操作FOR XML 查询的输出。
【解决方案2】:

您需要将dbo.tablename 替换为您的实际表格。另外我假设您使用的是 SQL Server 2005 或更高版本 - 指定总是有用的。

SELECT Number, Grades = STUFF((
    SELECT N', ' + Grade FROM dbo.tablename
    WHERE Number = x.Number 
    FOR XML PATH(''), 
    TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 2, N'')
FROM dbo.tablename AS x
GROUP BY Number;

在 SQL Server 2017 和 Azure SQL 数据库中,您可以使用新的聚合函数STRING_AGG(),在这种情况下会更整洁:

SELECT Number, Grades = STRING_AGG(Grade, N', ')
  FROM dbo.tablename
  GROUP BY Number;

【讨论】:

  • 对这些类型的查询使用 distinct 并不是最优的。在 Kirill Polishchuk 提供的答案中使用 group by 是更快的选择。这里逗号分隔的字符串为每一行构建一次,而不是为每组行构建一次。
  • @MikaelEriksson 请注意,在我针对 sys.all_columns 的情况下,与 GROUP BY 相比,DISTINCT 的性能实际上要好得多(后者在经过的时间上长 10 倍以上)。您是否对此进行了任何具体测试,还是理论上的?
  • 我对这里使用的结构进行了一些测试,表格中填充了spt_values x 3。结果是大约 4500 行分组。不同的查询需要 600 毫秒,组需要 300。这是在 SQL Server 2012 上。我的测试中的差异在 2008 年更大,但那也是在另一台计算机上,所以那里没有真正的结论。工作台上的读取也有很大差异。
  • @MikaelEriksson 恕我直言,陪审团仍然不在。当然,我在工作表上看到了更多读取,但我不能忽略 cpu/经过时间中如此重要的(并且可重复的,即使使用 dropcleanbuffers/freeproccache)增量。这也在 SQL Server 2012 上。在这种情况下分组了 640 行。
  • @MikaelEriksson 这样做会更有效率。我必须记住这一点,在很多情况下,我发现这两者是可以互换的,但在这种情况下,很清楚为什么它们实际上会有不同的行为。
猜你喜欢
  • 1970-01-01
  • 2013-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多