如何将重复字段聚合到单独的列中

How to aggregate repeating fields into seperate colums

以下情况,pos/neg_text 正在重复:

这是我的反馈table:

id  text-id    pos_text         neg_text       cat_id
1   1          nice people      null           21 
2   1          nice people      null           24 
3   1          nice people      null           27 
4   1          null             cold room      36
5   1          null             cold room      37

我想将所有这些数据放在一行中,例如:

id  text-id    pos_text         neg_text       pos_cat_id       neg_cat_id
1   1          nice people      cold room      "21,24,27"       "36,37"   

我的 SQL 查询应该是什么样的?我正在我的中间件中使用 TypeScript 实现一个算法来解决这个问题,也许有 DB 专家可以通过简单的 SQL-Query.

更优雅地解决这个问题

使用 SQL 服务器 2008

由于使用了这么旧版本的SQL服务器,这并不容易。您缺少 CONCAT 等用于隐式转换的简单工具,以及 STRING_AGG 等更新的功能,这意味着您需要使用 table 的 3 次扫描来实现 1 次扫描中可以完成的工作。

相反,我们需要在此处使用“旧”FOR XML PATH 方法来聚合值,并使用 CONVERT 而不是简单的 CONCAT(',',sq.catid)。我使用 3 作为长度,但您可能需要更长的长度。

WITH YourTable AS(
    SELECT *
    FROM (VALUES(1,1,'nice people',null,21), 
                (2,1,'nice people',null,24), 
                (3,1,'nice people',null,27), 
                (4,1,null,'cold room',36),
                (5,1,null,'cold room',37))V(id,textid,postext,negtext,catid))
SELECT MIN(ID) AS ID,
       textid,
       MAX(postext) AS postext,
       MAX(negtext) AS negtext,
       STUFF((SELECT ',' + CONVERT(varchar(3),sq.catid)
              FROM YourTable sq
              WHERE sq.textid = YT.textid
                AND sq.postext IS NOT NULL
              ORDER BY sq.id
              FOR XML PATH(''),TYPE).value('(./text())[1]','varchar(MAX)'),1,1,'') AS poscatid,
       STUFF((SELECT ',' + CONVERT(varchar(3),sq.catid)
              FROM YourTable sq
              WHERE sq.textid = YT.textid
                AND sq.negtext IS NOT NULL
              ORDER BY sq.id
              FOR XML PATH(''),TYPE).value('(./text())[1]','varchar(MAX)'),1,1,'') AS negtextid
FROM YourTable YT
GROUP BY YT.textid;

db<>fiddle

请注意,这就是 SQL 的最新版本的简单程度:

SELECT MIN(ID) AS ID,
       textid,
       MAX(postext) AS postext,
       MAX(negtext) AS negtext,
       STRING_AGG(CASE WHEN postext IS NOT NULL THEN catid END,',') WITHIN GROUP (ORDER BY ID) AS poscatid,
       STRING_AGG(CASE WHEN negtext IS NOT NULL THEN catid END,',') WITHIN GROUP (ORDER BY ID) AS negcatid
FROM YourTable
GROUP BY textid;