我真的坚持使用Postgresql中的复杂查询。用例是系统具有用户,组和策略。用户可以属于多个组,策略可以属于组或用户。建模如下:
CREATE TABLE "user" (
id BIGSERIAL NOT NULL,
username CHARACTER VARYING(64) NOT NULL UNIQUE,
hashed_password CHARACTER VARYING(64) NOT NULL,
ldap BOOLEAN DEFAULT FALSE,
PRIMARY KEY (id)
);
CREATE TABLE "group" (
id BIGSERIAL NOT NULL,
name CHARACTER VARYING(64) NOT NULL UNIQUE,
PRIMARY KEY (id)
);
CREATE TABLE "user_group" (
user_id BIGINT NOT NULL,
group_id BIGINT NOT NULL,
PRIMARY KEY (user_id, group_id),
FOREIGN KEY (user_id) REFERENCES "user"(id),
FOREIGN KEY (group_id) REFERENCES "group"(id)
);
CREATE TABLE "policy" (
id BIGSERIAL NOT NULL,
user_id BIGINT,
group_id BIGINT,
effect VARCHAR(5),
action TEXT,
resource TEXT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES "user"(id),
FOREIGN KEY (group_id) REFERENCES "group"(id)
);
现在我需要根据用户ID和基于用户组的策略检查用户的策略,并且我想将它们与用户信息一起加入。
我想出了这一点,但是ID=1
的用户应该拥有政策,因为他在ID=1
的群组中时,这不会显示。
现在在政策中的数据就是这样:
id=1
user_id=<null>
group_id=1
...
使用的查询是:
SELECT
p.effect,
p.action,
p.resource,
u.*
FROM policy AS p
LEFT JOIN "user" AS u ON p.user_id = u.id
LEFT JOIN "group" AS g ON p.group_id = g.id
LEFT JOIN user_group AS ug ON u.id = ug.user_id
WHERE p.user_id = ug.user_id OR p.group_id = ug.group_id AND ug.user_id = 1;
答案 0 :(得分:1)
您需要政策记录。因此,请从政策中进行选择,并在EXISTS
子句中使用IN
或WHERE
。您需要用户1的所有策略。这是策略的用户ID为1或策略的组ID连接到此用户的位置。
只需要两个表:策略表和将用户链接到组的桥接表。
select *
from policy
where user_id = 1
or group_id in (select group_id from user_group where user_id = 1);
更新:您已更改了您的请求。您现在也想显示用户信息。这是一个额外的加入。
select *
from policy p
cross join (select * from "user" where id = 1) u
where p.user_id = 1
or p.group_id in (select group_id from user_group where user_id = 1);
如果你更喜欢它,你可以用= 1
替换主查询的WHERE
子句中的两个= u.id
。我这样做: - )
答案 1 :(得分:0)
我认为你的join
条件错了。我想这就是你想要的:
SELECT p.effect, p.action, p.resource
FROM "user" u JOIN
policy p
ON p.user_id = u.id JOIN
user_group ug
ON u.id = ug.user_id JOIN
"group" g
ON ug.group_id = g.id AND p.group_id = ug.group_id
WHERE ug.user_id = 1;
policy
中的群组与user_groups
中的群组有何关联,这有点令人困惑。