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

时间:2013-11-28 23:07:21

标签: sql-server group-by aggregate-functions sql-server-group-concat

我正在寻找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”调用?手动迭代数据集并在控制台应用程序中构建新表?或者有什么我想念的东西?

1 个答案:

答案 0 :(得分:2)

试试这个:

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