2017-09-18 11 views
0

私は本当にPostgresqlの複雑なクエリに悩まされています。ユースケースは、システムにユーザー、グループ、およびポリシーがあることです。ユーザーは複数のグループに属し、ポリシーはグループまたはユーザーのいずれかに属します。これは以下のようにモデル化される。SQLで複数のテーブルからリレーションを選択

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; 
+1

クエリを表示してください –

+0

@VaoTsunがクエリを追加しました。 – mmjmanders

+0

「USER」と「GROUP」の両方が予約語です。私は複数のテーブル名とsingularis列名を好む。 – jarlh

答えて

1

ポリシー・レコードをしたいです。したがって、ポリシーから選択し、WHERE句にEXISTSまたはINを使用してください。ユーザー1のすべてのポリシーが必要です。これは、ポリシーのユーザーIDが1であるか、ポリシーのグループIDがこのユーザーに接続されている場所です。

必要なテーブルは2つだけです。ポリシーテーブルと、ユーザーをグループにリンクするブリッジテーブルです。

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); 

そして、あなたはより良いそれを好きならば、あなたは= u.idをメインクエリのWHERE句で2 = 1を置き換えることができます。私は:-)

+0

このクエリは0の結果を示します – mmjmanders

+0

申し訳ありませんが、その2番目のクエリはナンセンスでした。私は更新するつもりです...今は動作しなければなりません。ユーザー1のレコードとのクロス結合が必要です。 –

+0

ありがとうございました – mmjmanders

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のグループに関連するべきかについて少し混乱しています。

+0

ユーザーは彼がいるグループのポリシーを継承します。このクエリは何の結果も与えていません – mmjmanders