如何将重复字段聚合到单独的列中
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;
请注意,这就是 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;
以下情况,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;
请注意,这就是 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;