1

今天早上我的 SQL 感觉不起作用,我需要一些帮助。

我有 3 个主表,它们之间有两个用于多对多关系的中间表:userusers_groupsgroupgroups_permissionspermission. 每个permission都有一个name

我想写一个查询,给定一个权限名称和一个用户 ID,如果权限存在则返回相应的权限 ID ,如果用户有权限,则返回一个值,否则为 NULL。也就是说,我想知道权限是否存在以及用户是否在一个查询中具有权限。输出应如下所示:

                         |has_permission | does_not_have_permission
-------------------------------------------------------------------
permission_exists        |     (1,1)     |        (1,NULL)
permission_does_not_exist|      N/A      |        [0 rows]

现在,我能想到的查询看起来像这样:

SELECT p.id, ug.user_id
FROM permission AS p LEFT JOIN
     groups_permissions AS gp ON p.id = gp.permission_id LEFT JOIN
     group AS g ON gp.group_id = g.id LEFT JOIN
     users_groups AS ug ON ug.group_id = g.id AND ug.user_id = ?
WHERE p.name = ?;

问题是在某些情况下这会返回不止一行。我想我可以在它上面扔一个ORDER BY u.id DESC和一个LIMIT 1,但是这样会优化吗?我需要什么索引?是否有另一种方法可以编写此查询来快速轻松地获取我正在寻找的信息?

编辑:对于那些好奇的人,我使用的是 PostgreSQL,但如果可能的话,我希望查询与 db 无关。

4

3 回答 3

2

会为您的查询添加distinct工作吗?

SELECT distinct p.id, ug.user_id
FROM permission AS p LEFT JOIN
     groups_permissions AS gp ON p.id = gp.permission_id LEFT JOIN
     group AS g ON gp.group_id = g.id LEFT JOIN
     users_groups AS ug ON ug.group_id = g.id AND ug.user_id = ?
WHERE permission.name = ?;

我认为问题在于某些用户从不同的组成员中获得了相同的权限。

您评论中的问题可以通过聚合来解决:

SELECT p.id, max(ug.id),
       (case when max(ug.id) is null then 'DENIED' else 'ALLOWED' end)
FROM permission AS p LEFT JOIN
     groups_permissions AS gp ON p.id = gp.permission_id LEFT JOIN
     group AS g ON gp.group_id = g.id LEFT JOIN
     users_groups AS ug ON ug.group_id = g.id AND ug.user_id = ?
WHERE permission.name = ?
group by ug.id
于 2013-01-09T16:53:27.683 回答
1
SELECT p.id, u.user_id
FROM permission AS p 
  LEFT JOIN
    user AS u 
      ON  u.user_id = ? 
      AND EXISTS
          ( SELECT *
            FROM users_groups AS ug 
              JOIN groups_permissions AS gp 
                ON gp.group_id = ug.group_id
            WHERE p.id = gp.permission_id 
              AND u.user_id = ug.user_id
          )
WHERE p.name = ? ;
于 2013-01-09T17:31:41.280 回答
0

抱歉 - 刚刚看到原始问题底部的 PostreSQL 和 db 不可知句。此答案可能仅适用于 MS SQL Server。

如果用户属于具有相同权限的多个组,您可能会得到多行。在这种情况下,您需要聚合它们。像这样的东西会起作用吗?

WITH PermissionsForUser AS
(
SELECT
  p.id,
  u.id
FROM permissions p
LEFT JOIN groups_permissions gp
ON p.id = gp.permission_id
LEFT JOIN users_groups ug
ON ug.group_id = gp.group_id
LEFT JOIN users u
ON ug.user_id = u.id
WHERE p.name = @PermissionId
AND u.id = @UserId
)
SELECT
  MAX(p.id) AS permission_id
  MAX(u.id) AS user_id
FROM PermissionsForUser;
于 2013-01-09T16:33:03.630 回答