如何在没有附加查询的情况下在 SQL Server 中连接没有子查询的 GROUP BY 子句中的字符串?

Posted

技术标签:

【中文标题】如何在没有附加查询的情况下在 SQL Server 中连接没有子查询的 GROUP BY 子句中的字符串?【英文标题】:How can I concatenate strings in a GROUP BY clause without a subquery in SQL Server without an additional query? 【发布时间】:2013-11-28 23:07:21 【问题描述】:

我正在寻找与 SQL Server 2012 中的 GROUP_CONCAT() mysql 函数等效的函数 - 它使用子查询,解释如下:

CREATE TABLE Temp
( 
ID INT PRIMARY KEY NOT NULL IDENTITY(1,1),
ColA varchar(900) NULL,
ColB varchar(900) NULL
)

INSERT INTO Temp (ColA, ColB)
SELECT 'A', 'some' UNION ALL
SELECT 'A', 'thing' UNION ALL
SELECT 'A', 'and' UNION ALL
SELECT 'B', 'some' UNION ALL
SELECT 'B', 'more' UNION ALL
SELECT 'B', 'and' UNION ALL
SELECT 'B', 'more' UNION ALL
SELECT 'C', 'things' UNION ALL
SELECT 'C', 'things'

-- Desired Output. Note that the lists are in descending order of frequency ('more' appears twice)
ColA, Frequency, ColBs
'B', 4, 'more, some, and'
'A', 3, 'some, thing, and'
'C', 2, 'things'

SELECT 
    ColA, 
    COUNT(*) as Frequency, 
    GROUP_CONCAT(ColB) --Would be nice
FROM Temp
GROUP BY ColA
ORDER BY Frequency DESC

在 SQL Server 中对此的常见答案是在子查询上使用 STUFF()。就我而言,性能简直无法接受(2 亿条记录,每个子查询 26 秒 * 2 亿 = 164 年)。

SELECT 
    ColA, 
    COUNT(*) as Frequency, 
    ISNULL(
        STUFF((
            SELECT ', ' + ColBs FROM
                (SELECT ColBs, Count(*) as Frequency
                FROM Temp sub
                WHERE sub.ColA = t.ColA
                GROUP BY ColB
                ORDER BY Frequency DESC)
            FOR XML PATH('')
        ), 1, 2, '')
    ), '') as ColBs --Would take 164 years on the entire data set
FROM Temp t
GROUP BY ColA
ORDER BY Frequency DESC

所需的输出是每个唯一 ColA 的 ColB 值,按出现的降序分组在一起,如上所示。但是,这需要通过表的 SINGLE QUERY 来完成。

我是否需要自己构建并放弃“GROUP BY”调用?手动迭代数据集并在控制台应用程序中构建新表?还是我缺少什么?

【问题讨论】:

您可以尝试使用基于光标的解决方案 (LOCAL FAST_FORWARD)。 您能举个例子回答一下吗? How to use GROUP BY to concatenate strings in SQL Server?的可能重复 你怎么知道我的答案在那里?我明确指出,由于性能原因,我不能像每个答案一样使用子查询。 @Stoleg 我不认为这个问题是重复的,因为我特别要求一个不使用任何子查询的解决方案。 “可能重复”中的所有答案都使用子查询。 【参考方案1】:

试试这个:

WITH prelim
AS
(
   SELECT
     cola
    ,colb
    ,count(*) AS recs
    ,row_number() over (partition BY cola ORDER BY count(*) DESC ,colb) AS recno
    ,Count(*) over (partition BY cola ) AS cnt
  FROM TEMP
  GROUP BY cola,colb ),
Group_Concat (recno,cnt,recs,cola,colbs)
AS
(
SELECT
    recno
    ,cnt
    ,recs
    ,cola
    ,CAST (colb AS varchar(MAX)) AS colbs
FROM
    prelim
WHERE
    recno=1
UNION ALL
SELECT
    p.recno
    ,p.cnt
    ,g.recs+p.recs
    ,p.cola
    , g.colbs + ', ' + CAST (p.colb AS varchar(MAX)) AS colbs
FROM
    prelim p
    JOIN Group_Concat g ON p.cola=g.cola AND p.recno=g.recno+1
)

SELECT COLA,Recs as Frequency,COLBS 
FROM Group_Concat
where recno=cnt
order by cola

【讨论】:

这是在给定的数据集上工作,我会在我更大的数据集上尝试它,如果需要几天,我会将此标记为答案。谢谢! 如果性能仍然是一个问题,我唯一能想到的就是将 prelim cte 替换为 @table 变量,并在 cola 和 recno 上使用聚集索引。性能将在很大程度上取决于第一组减少了多少总记录数。从手机发帖所以不能发布sql atm。稍后会这样做。 这不算在 OP 上下文中使用子查询吗? 确实如此,我要检查它是否更快。如果是(可以在不到一天的时间内完成),如果在没有子查询的情况下没有尝试这样做,我仍然会将其标记为答案。我不知道为什么没有内置连接聚合函数。 从技术上讲,它使用 additional 查询,而不是每行的子查询。

以上是关于如何在没有附加查询的情况下在 SQL Server 中连接没有子查询的 GROUP BY 子句中的字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有 SQL Server Management Studio 的情况下在 SQL Server Express LocalDB 中使用 Visual Studio 2013 创建两个表之间的关

如何在不使用数据透视和反透视的情况下在 SQL Server 中水平显示数据?

如何在不使用pivot和unpivot的情况下在SQL Server中水平显示数据?

我可以在不使用 ROW_NUM () OVER (ORDER BY xxxxx) 的情况下在 Sql Server 中对查询进行分页吗?

如何在没有任何附加模块的情况下在迷你 Web 服务器中返回 json?

React Native - 如何在没有完全重新渲染的情况下在 ListView 中添加和附加数据