从SQL中的多个表中选择关系

时间:2017-09-18 12:39:56

标签: sql postgresql

我真的坚持使用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;

2 个答案:

答案 0 :(得分:1)

您需要政策记录。因此,请从政策中进行选择,并在EXISTS子句中使用INWHERE。您需要用户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中的群组有何关联,这有点令人困惑。