1

私のSQLセンスは今朝機能しておらず、助けが必要です。

私は3つのプライマリテーブルを持っており、それらの間の2つの中間テーブルは、多対多の関係に使用されます:user、、、、、および。それぞれにがあります。users_groupsgroupgroups_permissionspermissionpermissionname

I would like to write a query that, given a permission name and a user id, returns the corresponding permission id if the permission exists, and also returns a value if the user has the permission else NULL. That is to say, I want to know both if the permission exists and if the user has the permission in one query. The output should look something like this:

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

Right now, the query I can think of looks something like this:

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 = ?;

The problem is that this returns more than one row in certain cases. I could throw an ORDER BY u.id DESC and a LIMIT 1 onto it, I think, but will that optimize well? What are the indexes I need for that? Is there another way that I could write this query to get the info I am looking for quickly and easily?

edit: for those who are curious, I am using PostgreSQL, though I'd like the query to be db agnostic if possible.

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 に答える