SQL Server 2016:多列分组合并指定列值技术求助
问题:按5列分组合并第6列多行值(SQL Server 2016)
我有一批数据,其中5列内容完全相同,仅第6列存在差异。希望按这5列进行分组,将第6列的多行值合并为一行。尝试过CTE和STUFF函数但未达预期,多数示例仅处理两列场景;使用SQL Server 2016(版本130),无法使用STRING_AGG函数。
当前查询返回的数据
| 站点名称 | 页面标题 | 页面URL | 创建日期 | 过期日期 | 审核人 |
|---|---|---|---|---|---|
| xSite | sql concat | //abc.com/fr | 02/02/2023 | 28/02/2023 | James (jk jk@something.com) |
| xSite | sql concat | //abc.com/fr | 02/02/2023 | 28/02/2023 | David (dDel jk@something.com) |
| xSite | sql concat | //abc.com/fr | 02/02/2023 | 28/02/2023 | Ali (aLee aLee@something.com) |
| xSite | Join in SQL | //abc.com/vf | 18/02/2020 | 2/05/2022 | Ken (kK kk@something.com) |
| ySite | Just SQL | //abc.com/a | 31/01/2022 | 21/05/2023 |
期望返回的结果
| 站点名称 | 页面标题 | 页面URL | 创建日期 | 过期日期 | 审核人 |
|---|---|---|---|---|---|
| xSite | sql concat | //abc.com/fr | 02/02/2023 | 28/02/2023 | James (jk jk@something.com), David (dDel jk@something.com), Ali (aLee aLee@something.com) |
| xSite | Join in SQL | //abc.com/vf | 18/02/2020 | 2/05/2022 | Ken (kK kk@something.com) |
| ySite | Just SQL | //abc.com/a | 31/01/2022 | 21/05/2023 |
我尝试的SQL代码
WITH cte_contentExpiry AS ( SELECT c.sitename ,c.pagetitle ,c.pageurl ,c.dateCreated ,c.expiryDate ,a.userid FROM dbo.content c LEFT OUTER JOIN dbo.assignments a ON c.contentId = a.contentId WHERE c.active = 1 ) SELECT q.sitename ,q.pagetitle ,q.pageurl ,q.dateCreated ,q.expiryDate , STUFF((SELECT '; ' + u.fName + ' (' + u.userName + ' - ' + u.email + ')' FROM dbo.users u WHERE q.userId = u.userId FOR XML PATH('')), 1, 1, '') AS reviewer FROM cte_contentExpiry q GROUP BY q.sitename ,q.pagetitle ,q.pageurl ,q.dateCreated ,q.expiryDate ,q.userId
解决方案
你的核心问题是分组时包含了userId,导致每个不同的userId都会生成单独一行,无法实现按前5列合并的效果。此外,子查询需要关联的是前5列而非userId,才能将同一组下的所有审核人合并。
修正后的SQL代码如下:
WITH cte_contentExpiry AS ( SELECT c.sitename, c.pagetitle, c.pageurl, c.dateCreated, c.expiryDate, -- 提前拼接好审核人的完整信息 CONCAT(u.fName, ' (', u.userName, ' ', u.email, ')') AS reviewer_info FROM dbo.content c LEFT JOIN dbo.assignments a ON c.contentId = a.contentId LEFT JOIN dbo.users u ON a.userid = u.userId -- 直接关联用户表获取完整信息 WHERE c.active = 1 ) SELECT sitename, pagetitle, pageurl, dateCreated, expiryDate, -- 合并同一组的所有审核人 STUFF( (SELECT ', ' + reviewer_info FROM cte_contentExpiry sub WHERE sub.sitename = main.sitename AND sub.pagetitle = main.pagetitle AND sub.pageurl = main.pageurl AND sub.dateCreated = main.dateCreated AND sub.expiryDate = main.expiryDate FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '' -- 移除开头多余的', ' ) AS 审核人 FROM cte_contentExpiry main GROUP BY sitename, pagetitle, pageurl, dateCreated, expiryDate;
关键修正说明:
- 移除分组中的
userId,仅按需要合并的5列分组 - 子查询通过关联前5列,确保同一组的所有审核人都被纳入合并范围
- 使用
TYPE和.value('.', 'NVARCHAR(MAX)')避免特殊字符被转义(如<、>等) - 在CTE中提前拼接审核人信息,简化子查询逻辑
如果需要处理审核人为空的场景(如ySite的数据),可以用ISNULL将结果转为空字符串:
ISNULL( STUFF( (SELECT ', ' + reviewer_info FROM cte_contentExpiry sub WHERE sub.sitename = main.sitename AND sub.pagetitle = main.pagetitle AND sub.pageurl = main.pageurl AND sub.dateCreated = main.dateCreated AND sub.expiryDate = main.expiryDate FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '' ), '' ) AS 审核人
内容的提问来源于stack exchange,提问作者david-l
相关产品推荐
相关产品推荐

