帮我解决这个SQL查询

时间:2011-09-19 16:36:59

标签: sql sql-server-2008

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_UsersUsersRoles之间的多对多链接表。我想撤回以下信息:

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)。因此,基本上我想要提取的记录集将使每个用户仅以其最低访问级别角色名称列出一次。

我确信这很简单,但现在只是让我感到难过。

由于

5 个答案:

答案 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
    )

注意:这不会列出没有任何角色的用户。