You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SSMS中如何将多用户组合并为单个单元格逗号分隔值

问题根因

多表关联出现重复行,是因为AspNetUsers和UserGroups通过中间表UserGroupUsers是1对多关系,如果同时关联同样是1对多的角色表,还会产生笛卡尔积,导致同一条用户数据返回多行,直接在外层聚合很容易出现值重复、拼接错误的问题。

修正方案

不要直接关联多对多表后在外层聚合,先将用户组、角色这类一对多关联的数据提前按用户ID分组聚合,每个用户仅返回一行聚合结果,再关联用户主表、岗位、部门这类一对一关联的维度表,从根源上避免重复行。

以下是适配SQL Server 2017及以上版本(支持STRING_AGG)的可直接运行代码:

SELECT 
    a.FirstName, 
    a.LastName, 
    a.Email, 
    JSON_VALUE(p.NameJson,'$[0].Text') AS Position, 
    JSON_VALUE(d.NameJson,'$[0].Text') AS Department, 
    ug.Groups,
    sr.Roles
FROM AspNetUsers a
LEFT JOIN Positions p 
    ON a.PositionId = p.Id
LEFT JOIN Departments d
    ON a.DepartmentId = d.Id
-- 预聚合当前用户关联的所有用户组
LEFT JOIN (
    SELECT 
        ugu.User_Id,
        STRING_AGG(JSON_VALUE(ug.NameJson, '$[0].Text'), ', ') AS Groups
    FROM UserGroupUsers ugu
    INNER JOIN UserGroups ug
        ON ugu.UserGroup_Id = ug.Id
    GROUP BY ugu.User_Id
) ug ON a.Id = ug.User_Id
-- 预聚合当前用户关联的所有角色,避免多角色+多用户组产生笛卡尔积
LEFT JOIN (
    SELECT 
        ur.UserId,
        STRING_AGG(JSON_VALUE(sr.TitleJson, '$[0].Text'), ', ') AS Roles
    FROM UserRoles ur
    INNER JOIN SecurityRoles sr
        ON ur.RoleId = sr.Id
    GROUP BY ur.UserId
) sr ON a.Id = sr.UserId
ORDER BY a.LastName DESC

运行后即可得到预期结果:单个用户仅返回一行,Groups列会将所有所属用户组用逗号拼接展示,其余字段保持正常。

低版本兼容(SQL Server 2016及更早)

如果你使用的版本不支持STRING_AGG函数,将聚合子查询替换为FOR XML PATH + STUFF的写法即可,以用户组聚合为例,替换对应子查询部分:

LEFT JOIN (
    SELECT 
        ugu.User_Id,
        STUFF(
            (SELECT ', ' + JSON_VALUE(ug_sub.NameJson, '$[0].Text')
             FROM UserGroupUsers ugu_sub
             INNER JOIN UserGroups ug_sub 
                 ON ugu_sub.UserGroup_Id = ug_sub.Id
             WHERE ugu_sub.User_Id = ugu.User_Id
             FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)'),
            1, 2, ''
        ) AS Groups
    FROM UserGroupUsers ugu
    GROUP BY ugu.User_Id
) ug ON a.Id = ug.User_Id

角色部分的聚合逻辑和上面完全一致,替换对应字段和表名即可。

注意事项

  • 禁止直接在原查询外层套GROUP BY+STRING_AGG:如果用户同时拥有多个角色、多个用户组,直接JOIN会产生「角色数*用户组数」的笛卡尔积行,最终拼接出来的群组、角色值会出现无意义的重复。
  • 预聚合时已经完成了JSON字段的取值解析,外层查询不需要再重复调用JSON_VALUE处理组名、角色名字段。

内容的提问来源于stack exchange,提问作者Shawnlittrel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 01:57:16