连接表后如果不存在条件则选择行

问题描述 投票:0回答:1

我有4张桌子,

权限

id 蛞蝓 允许
1 创建 真实
2 编辑 真实
3 删除 真实
4 编辑

角色

id 蛞蝓
1 管理员
2 经理
3 用户

模型_权限

模型类型 型号_id permission_id
用户 1 4
角色 1 1
角色 1 2
角色 1 3

模型_角色

模型类型 型号_id 角色_id
用户 1 1
用户 2 1
用户 3 2
用户 3 3

在第一步中,我想获得用户的所有权限(假设 id=1),无论是“直接”分配还是通过角色, 这就是我想到的,它有效并返回正确的结果


select p.*
from permissions p
         join model_permissions mp on mp.permission_id = p.id
         join model_roles mr on mr.model_type = 'users' and mr.model_id = 1
where
    (
       (mp.model_type = 'users' and mp.model_id = 1)
        or
       (mr.role_id = mp.model_id and mp.model_type = 'roles')
    )

group by p.id;

我的下一步是检查用户是否具有特定权限,但是否有一行具有相同的

slug
allowed=false
我想得到空结果。

示例: id=1 的用户通过角色拥有

edit
权限 (allowed=true),还具有直接
edit
权限 (allowed=false) id=4(model_permissions 表),

因此,当我尝试检查用户是否具有

edit
权限时,在这种特殊情况下我想得到空(假)结果,我尝试过的


select p.*
from permissions p
         join model_permissions mp on mp.permission_id = p.id
         join model_roles mr on mr.model_type = 'users' and mr.model_id = 1
where
     (
        (mp.model_type = 'users' and mp.model_id = 1)
        or
        (mr.role_id = mp.model_id and mp.model_type = 'roles')
     )
  and
    not exists(select *
                 from permissions p2
                 where p2.allowed=false
                 and p2.slug=p.slug
                 )
  and
    p.slug = 'edit'

group by p.id;

它按预期工作,但是如果我从 model_permissions 中删除行

|users | 1  | 4  |
它仍然返回空,我想获得结果,因为该用户通过角色具有“编辑”权限

我已经尝试过上面的sql查询,当我在

p2.id=p.id
语句中使用
not exists
时,它总是返回结果,具有
allowed=true
值的结果:
| 2 | edit | true |

无需更改数据库架构的任何解决方案

sql mysql postgresql inner-join not-exists
1个回答
0
投票

修改后应该能满足您的需求了

SELECT p.*
FROM permissions p
JOIN model_permissions mp ON mp.permission_id = p.id
LEFT JOIN model_permissions mp_direct ON mp_direct.permission_id = p.id AND mp_direct.model_type = 'users' AND mp_direct.model_id = 1
JOIN model_roles mr ON mr.model_type = 'users' AND mr.model_id = 1
WHERE
    -- Either direct user permission or through roles
    (
       (mp.model_type = 'users' AND mp.model_id = 1)
        OR
       (mr.role_id = mp.model_id AND mp.model_type = 'roles')
    )
    -- Ensure we're checking for the specific permission
    AND p.slug = 'edit'
GROUP BY p.id
HAVING
    -- Ensure there's no direct denial overriding the permission
    MAX(CASE WHEN mp_direct.allowed IS NOT NULL THEN mp_direct.allowed ELSE TRUE END)
© www.soinside.com 2019 - 2024. All rights reserved.