3个表定义如下:
用户
User_ID INT
First_Name VARCHAR
Last_Name VARCHAR
Email VARCHAR
角色
Role_ID INT
Role_Name VARCHAR
Access_Level INT
Roles_Users
User_ID INT
Role_ID INT
Roles_Users
是Users
和Roles
之间的多对多链接表。我想撤回以下信息:
First_Name, Last_Name, Email, Role_Name
到目前为止我所拥有的是:
SELECT
U.First_Name,
U.Last_Name,
U.Email,
R.Name AS Role_Name
FROM Users U
INNER JOIN Roles_Users RU ON U.User_ID = RU.User_ID
INNER JOIN Roles R ON RU.Role_ID = R.Role_ID
棘手的部分(至少对我而言)是我只想为该特定用户撤回Role_Name
MIN(Access_Level)
。因此,基本上我想要提取的记录集将使每个用户仅以其最低访问级别角色名称列出一次。
我确信这很简单,但现在只是让我感到难过。
由于
答案 0 :(得分:3)
你可以将CTE(公用表表达式)与ROW_NUMBER
窗口函数结合使用,如下所示:
;WITH MinAccessData AS
(
SELECT
U.First_Name,
U.Last_Name,
U.Email,
R.Name AS Role_Name,
ROW_NUMBER() OVER(PARTITION BY U.User_ID ORDER BY R.Access_Level) AS RowNum
FROM Users U
INNER JOIN Roles_Users RU ON U.User_ID = RU.User_ID
INNER JOIN Roles R ON RU.Role_ID = R.Role_ID
)
SELECT *
FROM MinAccessData
WHERE RowNum = 1
CTE按User_ID
“分区”您的数据,例如每个用户获得一个“分区”。在该分区内,角色按Access_level
排序,最小的是第一个 - 因此它为RowNum = 1
- 为每个用户。
然后,您从CTE中选择所有RowNum = 1
的条目 - 这将为每个用户提供Access_Level
值最小的所有条目。
答案 1 :(得分:2)
没有CTE的替代品(只是在你的盒子里有另一个工具)
SELECT
U.First_Name,
U.Last_Name,
U.Email,
R.Name AS Role_Name
FROM Users U
INNER JOIN Roles_Users RU ON U.User_ID = RU.User_ID
INNER JOIN Roles R ON RU.Role_ID = R.Role_ID
INNER JOIN (SELECT
MIN(r.Access_Level) access_level,
ru.UserID,
FROM Roles r
INNER JOIN Roles_Users ru
ON r.Role_ID = ru.Role_ID
GROUP BY UserID
) minAccess
ON ru.UserId = minAccess.UserId
and ru.
ON r.access_level = minAccess .access_level
您也可以使用CROSS APPLY
SELECT
U.First_Name,
U.Last_Name,
U.Email,
R.Name AS Role_Name
FROM Users U
CROSS APPLY (SELECT TOP 1
Role_Name
FROM Roles_Users RU ON U.User_ID = RU.User_ID
INNER JOIN Roles R ON RU.Role_ID = R.Role_ID
WHERE u.user_id = ru.user_id
ORDER BY
Access_Level desc
)
答案 2 :(得分:1)
相关子查询:
SELECT
U.First_Name,
U.Last_Name,
U.Email,
(
select top 1 R.RName from Roles_Users RU ON U.User_ID = RU.User_ID
INNER JOIN Roles R ON RU.Role_ID = R.Role_ID
ORDER BY R.Access_Level
)
AS Role_Name
FROM Users U
在我看来,使用子查询更容易阅读和编写。在此代码中,相关子查询将返回每行1x。我喜欢@Conrad的内部联接解决方案,最简单,可能是性能最高的,也许我会使用它,只是将其作为另一种选择。
答案 3 :(得分:0)
未经测试,但它就是这样的
SELECT
U.First_Name,
U.Last_Name,
U.Email,
R.Role_Name
FROM Users U
JOIN Roles_Users RU ON U.User_ID = RU.User_ID
JOIN (
SELECT ROLE_ID, MIN(ROLE_NAME) ROLE_NAME
FROM ROLES
GROUP BY ROLE_ID
HAVING ACCESS_LEVEL = MIN(ACCESS_LEVEL)
) R ON RU.Role_ID = R.Role_ID
答案 4 :(得分:0)
SELECT Users.*, Roles.*
FROM
Users
JOIN Roles_Users ON Users.User_ID = Roles_Users.User_ID
JOIN Roles ON Roles.Role_ID = Roles_Users.Role_ID
WHERE
Access_Level = (
SELECT MIN(Access_Level)
FROM
Roles_Users
JOIN Roles ON Roles.Role_ID = Roles_Users.Role_ID
WHERE Users.User_ID = Roles_Users.User_ID
)
注意:这不会列出没有任何角色的用户。