SQLSERVER 中的 ListAGG

Posted

技术标签:

【中文标题】SQLSERVER 中的 ListAGG【英文标题】:ListAGG in SQLSERVER 【发布时间】:2013-03-06 20:14:57 【问题描述】:

我正在尝试在 SQLServer 中聚合一个“STRING”字段。我想在 Oracle 中找到与 LISTAGG 相同的函数。

你知道如何执行相同的功能或另一种方法吗?

例如,

Field A | Field B
1       |  A
1       |  B
2       |  A

我希望这个查询的结果是

1 | AB
2 | A

【问题讨论】:

请为 DISTINCT 投票:feedback.azure.com/forums/908035-sql-server/suggestions/… 【参考方案1】:

从SQL Server 2017 开始,可以使用STRING_AGG 函数,这大大简化了逻辑:

select FieldA, string_agg(FieldB, '') as data
from yourtable
group by FieldA

见SQL Fiddle with Demo

在 SQL Server 中,您可以使用 FOR XML PATH 获取结果:

select distinct t1.FieldA,
  STUFF((SELECT distinct '' + t2.FieldB
         from yourtable t2
         where t1.FieldA = t2.FieldA
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,0,'') data
from yourtable t1;

见SQL Fiddle with Demo

【讨论】:

我想在子选择中插入一个 order by 子句。你知道怎么插入这个子句吗? @user1557642 你想点什么?你想要颠倒的值吗?您可以轻松添加ORDER BY,请参阅此演示——sqlfiddle.com/#!3/0836c/7。在这种情况下,FieldA 的结果将显示 BA @user1557642 你可以使用ORDER BY,你只需要在子查询中包含一个GROUP BY,看这个演示——sqlfiddle.com/#!3/0836c/7 这个答案不再好。当前版本的 SQL Server 具有 STRING_AGG,它执行相同的工作并且在我的测试中总是更快。 @Qwertie 答案仍然有效,但我已更新答案以包含 STRING_AGG 函数版本。【参考方案2】:

mysql

SELECT FieldA
     , GROUP_CONCAT(FieldB ORDER BY FieldB SEPARATOR ',') AS FieldBs
  FROM TableName
 GROUP BY FieldA
 ORDER BY FieldA;

Oracle 和 DB2

SELECT FieldA
     , LISTAGG(FieldB, ',') WITHIN GROUP (ORDER BY FieldB) AS FieldBs
  FROM TableName
 GROUP BY FieldA
 ORDER BY FieldA;

PostgreSQL

SELECT FieldA
     , STRING_AGG(FieldB, ',' ORDER BY FieldB) AS FieldBs
  FROM TableName
 GROUP BY FieldA
 ORDER BY FieldA;

SQL 服务器

SQL Server ≥ 2017 和 Azure SQL

SELECT FieldA
     , STRING_AGG(FieldB, ',') WITHIN GROUP (ORDER BY FieldB) AS FieldBs
  FROM TableName
 GROUP BY FieldA
 ORDER BY FieldA;

SQL Server ≤ 2016(包括 CTE 以鼓励DRY principle)

  WITH CTE_TableName AS (
       SELECT FieldA, FieldB
         FROM TableName)
SELECT t0.FieldA
     , STUFF((
       SELECT ',' + t1.FieldB
         FROM CTE_TableName t1
        WHERE t1.FieldA = t0.FieldA
        ORDER BY t1.FieldB
          FOR XML PATH('')), 1, LEN(','), '') AS FieldBs
  FROM CTE_TableName t0
 GROUP BY t0.FieldA
 ORDER BY FieldA;

SQLite

排序需要 CTE 或子查询

  WITH CTE_TableName AS (
       SELECT FieldA, FieldB
         FROM TableName
        ORDER BY FieldA, FieldB)
SELECT FieldA
     , GROUP_CONCAT(FieldB, ',') AS FieldBs
  FROM CTE_TableName
 GROUP BY FieldA
 ORDER BY FieldA;

无需订购

SELECT FieldA
     , GROUP_CONCAT(FieldB, ',') AS FieldBs
  FROM TableName
 GROUP BY FieldA
 ORDER BY FieldA;

【讨论】:

很好的答案 - 比标记的答案更简洁+还提到了其他 sql 方言。用于此的 sqlserver 语法非常不直观。我也很惊讶 select in stuff 周围的额外括号是必要的。 @manas_kumar 但是……你为什么使用 STUFF?这是不必要的。我错过了什么吗? @Ricardo_C STUFF 在这里被用来删除前导逗号。 要完整,这需要添加到sql server示例中:***.com/a/8856789它可以防止某些字符被XML标签替换。 @DanLenski 似乎不是这样,因为我现在在我的另一台显示器上成功引用了cte,我想你没有正确构建你的查询?【参考方案3】:

在 SQL Server 2017 中添加了STRING_AGG:

SELECT t.name,STRING_AGG (c.name, ',') AS csv
FROM sys.tables t
JOIN sys.columns c on t.object_id = c.object_id
GROUP BY t.name
ORDER BY 1

另外,STRING_SPLIT 对于相反的情况很有用,并且在 SQL Server 2016 中可用

【讨论】:

STRING_AGG / STRING_SPLIT 最近也被添加到 Azure SQL 数据库中,任何碰巧登陆该平台的人也可以使用。 注意:vNext 已命名为 SQL Server 2017 你知道如何使用 distinct c.name,所以所有连接的名称都是唯一的吗?【参考方案4】:

这可能对某人也有用..

即对于数据分析师和数据分析类型的目的..(即不分组)..

在 SQL*Server 2017 String_agg 函数存在之前..

(即只返回一行..)

select distinct
SUBSTRING (
stuff(( select distinct ',' + [FieldB] from tablename order by 1 FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') 
,1,0,'' ) 
,2,9999)
from 
    tablename 

例如返回逗号分隔值 A,B

【讨论】:

以上是关于SQLSERVER 中的 ListAGG的主要内容,如果未能解决你的问题,请参考以下文章

SqlServer中的系统数据库

SqlServer中的dbo是什么意思

如何获取sqlserver某个表中的字段数目

SQLServer中的死锁的介绍

SQLServer2008中的Merge

什么是sqlserver中的事务