如果不在角色(admin)中,则不选择userId,在一个用户中选择多个角色

时间:2014-10-21 14:25:27

标签: sql sql-server

是否可以仅选择具有管理员角色(角色ID = 3)的用户的id而不使用NOT IN(与roleid相同的查询)?
每个用户都有不同的角色(用户,经理,管理员等)。

SELECT appUserInGroups.UserId, appRoles.RoleName, appRoles.RoleId
FROM appGroupInRoles 
        INNER JOIN appRoles ON appGroupInRoles.RoleId = appRoles.RoleId 
        INNER JOIN appUserInGroups ON appGroupInRoles.GroupId = appUserInGroups.GroupId 
        INNER JOIN appApplications ON appRoles.ApplicationId = appApplications.ApplicationId
WHERE appGroupInRoles.UserId not in ( SELECT appUserInGroups.UserId
                                        FROM appGroupInRoles 
                                          INNER JOIN appRoles ON appGroupInRoles.RoleId = appRoles.RoleId 
                                          INNER JOIN appUserInGroups ON appGroupInRoles.GroupId = appUserInGroups.GroupId 
                                         INNER JOIN appApplications ON appRoles.ApplicationId = appApplications.ApplicationId
                                          WHERE appGroupInRoles.RoleId = 3)

NOT IN完全杀死了性能。
用户角色预览:
User Roles preview

3 个答案:

答案 0 :(得分:2)

试试这个:

WITH Admins AS
(
   SELECT appUserInGroups.UserId AS uID
   FROM appGroupInRoles 
   INNER JOIN appUserInGroups ON appGroupInRoles.GroupId = appUserInGroups.GroupId 
   WHERE appGroupInRoles.RoleId = 3
)
SELECT appUserInGroups.UserId, appRoles.RoleName, appRoles.RoleId
FROM appGroupInRoles 
INNER JOIN appRoles ON appGroupInRoles.RoleId = appRoles.RoleId 
INNER JOIN appUserInGroups ON appGroupInRoles.GroupId = appUserInGroups.GroupId 
INNER JOIN appApplications ON appRoles.ApplicationId = appApplications.ApplicationId
LEFT JOIN Admins on appGroupInRoles.UserId = Admins.uID
WHERE Admins.uID is null

我从子查询中删除了一些额外的连接,并将其添加为CTE。我还使用了一个左连接而不是in(实际上应该在执行计划中编译相同)但添加它以向您显示“另一种方式”。

如果优化器运行良好,它应具有与以下相同的确切执行计划。

SELECT appUserInGroups.UserId, appRoles.RoleName, appRoles.RoleId
FROM appGroupInRoles 
INNER JOIN appRoles ON appGroupInRoles.RoleId = appRoles.RoleId 
INNER JOIN appUserInGroups ON appGroupInRoles.GroupId = appUserInGroups.GroupId 
INNER JOIN appApplications ON appRoles.ApplicationId = appApplications.ApplicationId
WHERE appGroupInRoles.UserId NOT IN (
   SELECT appUserInGroups.UserId AS uID
   FROM appGroupInRoles 
   INNER JOIN appUserInGroups ON appGroupInRoles.GroupId = appUserInGroups.GroupId 
   WHERE appGroupInRoles.RoleId = 3
)

编辑:请参阅评论中的链接以获取一篇很好的帖子,解释为什么您应该始终在SQL Server上使用NOT EXISTS。随机附注;根据我的经验,你应该在DB2上使用NOT IN

答案 1 :(得分:1)

尝试排除加入:

SELECT u.UserId, r.RoleName, r.RoleId
FROM appUserInGroups u
INNER JOIN appGroupInRoles g on g.GroupId = u.GroupId
INNER JOIN appRoles r ON r.RoleId = g.RoleId
LEFT JOIN (
    --Admin Users
    SELECT u.UserId
    FROM appUserInGroups u
    INNER JOIN appGroupInRoles g on g.GroupId = u.GroupId and g.RoleID=3
) a on a.UserId = u.UserId
WHERE a.UserId IS NULL

不确定你在使用appApplications表做了什么,看起来你在桌子上看的顺序有点奇怪......就像你从中间开始一样。

使用NOT EXISTS查询,您或许可以做得更好。

答案 2 :(得分:0)

您可以使用分析功能告诉您用户是否有角色3.但我不知道这是否更快。

select distinct userid, rolename, roleid
from
(
  SELECT 
    appUserInGroups.UserId, 
    appRoles.RoleName, 
    appRoles.RoleId,
    max(case when appRoles.RoleId = 3 then 1 else 0 end) over (partition by appUserInGroups.UserId) as has3
  FROM appGroupInRoles 
  INNER JOIN appRoles ON appGroupInRoles.RoleId = appRoles.RoleId 
  INNER JOIN appUserInGroups ON appGroupInRoles.GroupId = appUserInGroups.GroupId 
  INNER JOIN appApplications ON appRoles.ApplicationId = appApplications.ApplicationId
)
where has3 = 0;

我还添加了DISTINCT,因为用户可以通过不同组的成员身份获得角色,因此您可以在不使用DISTINCT的情况下获得重复项。