SQL 选择查询用户的角色/权限

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

我有一个具有多个多对多关系的数据库设计,并且正在尝试编写一个

SELECT
语句来检索带有 ONE ROW PER USER 的结果集。为此,我想将权限聚合到单个列中。

在应用的数据库设计中,一个用户可以有多个权限,一个角色可以有多个权限,一个用户也可以有多个角色,从而使用户的权限复合化。

以下是相关表格:

// Main tables
user:
- id
- username
- email

role:
- id
- name
- display_name

permission:
- id
- name
- display_name

// Many-to-many connector tables
user_role:
- user_id
- role_id

user_permission:
- user_id
- permission_id

(不好)我创建了一个成功聚合用户权限的查询,因为它只是单个聚合。但是,我似乎无法弄清楚在添加角色权限时如何获取二维聚合。

(更好)从下面的查询中,我希望至少有一个名为“roles_permissions_array”的第六列,它在伪代码中表示为:“对于在‘user_role_array’列中找到的每个角色,选择所有角色的数组权限。”

(最好)更进一步,最好还有一个查询版本,将所有权限(直接用户权限和角色权限)合并到单个列(去重复)中,这样我们就可以查看每个用户所有权限的单一来源。在这种情况下,输出列将为:

"user_id"
"user_name"
"user_email"
"user_role_array"
"user_permissions_array"
。最后一个将是所有用户权限和所有角色权限的合并数组

这是我尝试的开始:

SELECT DISTINCT 
    -- "user" columns
    u.id as "user_id", u.user_name as "user_user_name", u.email as "user_email",
    p_agg.user_permissions_array,
    r_agg.user_role_array
    FROM users."user" u
-- REGULAR JOINS
LEFT JOIN users.user_role ur on ur.user_id = u.id
LEFT JOIN users.role_permission rp on ur.role_id = rp.role_id
-- START AGGREGATES
LEFT JOIN (
    SELECT array_agg(r.name) as user_role_array, ur.user_id
    FROM users.user_role ur
    JOIN users.role r on r.id = ur.role_id
    GROUP BY ur.user_id
) r_agg using(user_id)
LEFT JOIN (
    SELECT array_agg(p.name) as user_permissions_array, up.user_id
    FROM users.user_permission up
    JOIN users.permission p on up.permission_id = p.id
    GROUP BY up.user_id
) p_agg using(user_id)
-- rp_agg_parent
-- NOT WORKING FROM HERE DOWN
LEFT JOIN (
    SELECT array_agg(role_permission_array) as two_dimensional_role_permissions_array
    FROM (
        SELECT p.role_id, r.name as "role_name", array_agg(p.permission_name) as "role_permission_array"
        FROM (
            SELECT r.id as "role_id", r.name as "role_name", p.name as "permission_name"
            FROM users.role_permission rp
            JOIN users.role r on r.id = rp.role_id
            JOIN users.permission p on p.id = rp.permission_id
            GROUP BY p.name, r.name, r.id
            ORDER BY p.name
        ) as p
        JOIN users.user_role ur on ur.role_id = p.role_id
        JOIN users.role r on r.id = ur.role_id
        GROUP BY r.name, p.role_id
        order by role_name
    ) AS rp_agg_sub
    JOIN users.role_permission rp on rp.role_id = rp_agg_sub.role_id
    GROUP BY rp_agg_sub.role_name
) rp_agg_parent using(p_role_id)
order by u.user_name;

但我只是收到一个错误:

"...column "p_role_id" specified in USING clause does not exist in left table"
。我怀疑即使我克服了这个错误,我可能仍然无法返回所需的结果集。有什么想法吗?

postgresql left-join array-agg
1个回答
0
投票

这个问题对我来说并不是100%清楚,但我的解释如下:

  • 有用户、角色和权限。
  • 角色是一组权限(角色不一定是不相交的集合)。
  • 可以将多个角色分配给同一用户。
  • 此外,可以直接向用户授予多个权限(而不是通过角色)。
  • 您想获得:
    • 所有用户信息
    • 所有分配角色的名称
    • 删除所有权限的重复名称(无论是直接权限还是通过角色)。
  • 所有表都位于
    users
    模式中。

试试这个:

SELECT
    u.id AS user_id,
    u.username AS user_name,
    u.email AS user_email,
    ARRAY_AGG(DISTINCT r.name ORDER BY r.name) AS user_role_array,
    ARRAY_AGG(DISTINCT p.name ORDER BY p.name) AS user_permission_array
FROM users.user u
LEFT JOIN users.user_role ur ON ur.user_id = u.id
LEFT JOIN users.role r ON r.id = ur.role_id
LEFT JOIN users.role_permission rp ON rp.role_id = r.id
LEFT JOIN users.user_permission up ON up.user_id = u.id
LEFT JOIN users.permission p ON p.id IN (rp.permission_id, up.permission_id)
GROUP BY u.id
ORDER BY u.username;
© www.soinside.com 2019 - 2024. All rights reserved.