SQL:从单个查询列出多对多

时间:2010-11-17 20:51:25

标签: sql-server tsql

我有3个表代表“用户”,“角色”和多对多的“UsersInRoles” - 用键:UserId,RoleId; pertinant columns:UserName,RoleName

在admin html应用程序中,我想显示所有用户及其所在角色的列表。从SQL,我正在尝试构建一个将返回此信息的查询。应该分隔角色列表,以便我可以进行适当的演示操作(取决于演示平台,例如用BR标记替换分隔符)。

对用户列表使用一个选择,然后为每个用户单独选择以获得角色是直截了当的,但是尝试构建输出以下内容的单个选择让我感到难过。

UserId  UserName  Roles
------  --------  -----
1       user1     Admin,Guest,PowerUser
2       user2     Guest
3       user3
4       user4     PowerUser,Guest

提前致谢,
--ed

- 编辑 -
现在使用以下查询(感谢所有人,尤其是Raymund& his blog):

WITH RolesList AS
(
  SELECT u.UserName,
  (
    SELECT r.RoleName + ',' AS 'data()'
    FROM Roles r
    JOIN UsersInRoles ur ON ur.RoleId = r.RoleId
    WHERE ur.UserId = u.UserId FOR XML PATH('')
  ) AS RolesCSV
  FROM Users u
) SELECT UserName, LEFT(RolesCSV, LEN(RolesCSV)-1) AS RolesCSV FROM RolesList

3 个答案:

答案 0 :(得分:3)

继承你的解决方案:

Converting / Parsing Rows to Delimited string column in SQL

修改

如果您需要进一步明确,请回​​答

WITH UserList as
(
SELECT UserID, UserName,
(SELECT 
RoleName + ',' AS 'data()'
FROM Roles
INNER JOIN 
UsersInRoles 
ON 
Roles.RoleID = UsersInRoles.RoleID
WHERE
UsersInRoles.UserID = Users.UserID FOR XML PATH('')) AS RoleCSV
FROM Users
)
SELECT UserID, UserName, LEFT(RoleCSV, LEN(RoleCSV)-1) as RoleCSV from UserList

答案 1 :(得分:2)

SQL Server 2005 +:

SELECT u.user_id,
       u.username,
       STUFF(ISNULL(SELECT ', ' + r.role_name
                      FROM USERSINROLES uir
                  JOIN ROLES r ON r.role_id = uir.role_id
                 WHERE uir.user_id = u.user_id
              GROUP BY r.role_name
                   FOR XML PATH ('')), ''), 1, 2, '')
  FROM USERS u

答案 2 :(得分:0)

由于@OMG小马指出我原来的“转动”反应不符合这个问题的标记,让我推迟他的解决方案。但是,我还是想提一个替代方案:

  

应该分隔角色列表   所以我可以做到合适   演示操作(取决于   在演示平台上,如替换   带有BR标签的分隔符。)

如果您正在提供分隔符,那么您的表示层可以(可能)将组合值分开,为什么不将它们单独返回,或者只返回加入多对多表的结果(留下一堆重复项),只需在表示层处理结果?

有两个论点:

  • C#之类的字符串操作通常比SQL
  • 中的字符串操作更快/更少痛苦
  • 更好地分离关注点 - 您的数据层可以简单地返回每个用户的一组角色,而不关心数据的呈现方式

在你的情况下,这些都不是令人信服的,但我希望我提供了深思熟虑的食物。