【问题标题】:How can I select all users who have a collection of permissions and not one specific permission SQL?如何选择具有一组权限而不是一个特定权限 SQL 的所有用户?
【发布时间】:2016-06-06 10:56:38
【问题描述】:

我的 SQL Server 数据库中有以下表格;

用户帐户

Username |   UserId
Joe      |        1
Hannah   |        2
Jack     |        3
Jill     |        4

权限

Permission |   PermissionId
p1         |        1
p2         |        2
p3         |        3
p4         |        4

用户权限

UserId  |  PermissionId
1       |  1
1       |  2
1       |  3
1       |  4
2       |  1
2       |  2
2       |  4
3       |  1
3       |  2
3       |  3
4       |  2
4       |  3
4       |  4

我想返回用户具有权限 p1 和 p2 但没有权限 p3 的用户名集合。

Username
Hannah

我得到的最接近的是这个;

SELECT ua.Username
FROM UserPermission up
JOIN UserAccount ua ON ua.UserID = up.UserId
JOIN Permission p ON p.PermissionId = up.PermissionId
WHERE p.Name = 'p1' OR p.Name = 'p2' 
GROUP BY up.UserId,ua.Username
HAVING COUNT(up.UserId) = 2

这只会返回具有权限 p1 和 p2 的用户(感觉就像我走错了方向)

显示结果集的最佳方式是什么(如果我想要拥有 p1 和 p2 但没有 p3 或 p4 的用户获得 +1!)?

谢谢。

【问题讨论】:

  • 你正朝着正确的方向前进。我唯一要做的整理是p.Name IN ('p1', 'p2')
  • 不排除也有p3的用户
  • 我不知道您究竟将什么存储为权限的“名称”,但如果可能的话,最好在 WHERE 子句中通过它们的 ID 来引用它们。

标签: sql sql-server tsql select


【解决方案1】:

你可以继续你正在使用的想法。唯一的区别是删除where 子句并增强having 子句:

SELECT u.Username
FROM UserPermission up JOIN
     UserAccount ua
     ON ua.UserID = up.UserId JOIN
     Permission p
     ON p.PermissionId = up.PermissionId
GROUP BY up.UserId,u.Username
HAVING SUM(CASE WHEN p.name = 'p1' THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN p.name = 'p2' THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN p.name IN ('p3', 'p4') THEN 1 ELSE 0 END) = 0;

【讨论】:

    【解决方案2】:
    SELECT  ua.UserName
    FROM UserPermission up
    LEFT JOIN UserAccount ua
        ON ua.UserId = up.UserId
    LEFT JOIN Permission p
        ON p.PermissionId = up.PermissionId
    GROUP BY ua.UserName
    HAVING SUM (CASE WHEN p.Permission IN ('p1','p2') THEN 2 WHEN p.Permission = 'p3' THEN 1 ELSE 0 END) = 4
    

    输出:

    UserName
    Hannah
    

    【讨论】:

      【解决方案3】:

      我使用实体框架,它为这样的查询提供了以下生成的 SQL:

      SELECT
          [Extent1].[Id] AS [Id],
          [Extent1].[Name] AS [Name]
          FROM [dbo].[Users] AS [Extent1]
          WHERE ( EXISTS (SELECT
              1 AS [C1]
              FROM [dbo].[UserPermissions] AS [Extent2]
              WHERE ([Extent1].[Id] = [Extent2].[User_Id]) AND (1 = [Extent2].[Permission_Id])
          )) AND ( EXISTS (SELECT
              1 AS [C1]
              FROM [dbo].[UserPermissions] AS [Extent3]
              WHERE ([Extent1].[Id] = [Extent3].[User_Id]) AND (2 = [Extent3].[Permission_Id])
          )) AND ( NOT EXISTS (SELECT
              1 AS [C1]
              FROM [dbo].[UserPermissions] AS [Extent4]
              WHERE ([Extent1].[Id] = [Extent4].[User_Id]) AND (3 = [Extent4].[Permission_Id])
          ))
      

      这可能更有效,我喜欢使用EXISTS 自己以获得更好的性能。您可能需要重写它以提高可读性并将列/表名称与您的数据库模型匹配。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-08
        • 2014-05-18
        • 2018-12-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多