2016-12-01 20 views
4

的一個子集:SQL:選擇行其不同的值是另一個表的假設下表中不同的值

plan_role 

id | plan_id | role_id 
----+---------+--------- 
    7 |  1 |  10 
    8 |  1 |  20 
    9 |  1 |  30 
10 |  2 |  10 
11 |  2 |  20 
12 |  3 |  30 
13 |  4 |  40 

user_role 

id | user_id | role_id 
----+---------+--------- 
    8 |  100 |  10 
    9 |  100 |  20 
10 |  100 |  40 
11 |  200 |  10 
12 |  200 |  20 
13 |  200 |  30 
14 |  200 |  40 

什麼是SQL查詢,將返回所有plan_ids這樣給定的user_id的一套role_ids的是一個超集plan_ids的role_id集合?

換句話說,我如何找到給定用戶的計劃,以便用戶至少與每個計劃共享所有角色。

例如,user_id 100應返回plan_id第2,第4和user_id 200應該返回1,2,3,4,

爲了方便起見,這裏是我使用的設置:

CREATE TABLE plan_role(
    id serial PRIMARY KEY, 
    plan_id integer NOT NULL, 
    role_id integer NOT NULL 
); 

CREATE TABLE user_role(
    id serial PRIMARY KEY, 
    user_id integer NOT NULL, 
    role_id integer NOT NULL 
); 

INSERT INTO plan_role (plan_id, role_id) VALUES (1, 10); 
INSERT INTO plan_role (plan_id, role_id) VALUES (1, 20); 
INSERT INTO plan_role (plan_id, role_id) VALUES (1, 30); 
INSERT INTO plan_role (plan_id, role_id) VALUES (2, 10); 
INSERT INTO plan_role (plan_id, role_id) VALUES (2, 20); 
INSERT INTO plan_role (plan_id, role_id) VALUES (3, 30); 
INSERT INTO plan_role (plan_id, role_id) VALUES (4, 40); 

INSERT INTO user_role (user_id, role_id) VALUES (100, 10); 
INSERT INTO user_role (user_id, role_id) VALUES (100, 20); 
INSERT INTO user_role (user_id, role_id) VALUES (100, 40); 
INSERT INTO user_role (user_id, role_id) VALUES (200, 10); 
INSERT INTO user_role (user_id, role_id) VALUES (200, 20); 
INSERT INTO user_role (user_id, role_id) VALUES (200, 30); 
INSERT INTO user_role (user_id, role_id) VALUES (200, 40); 

回答

3

我只是在這裏用LEFT JOIN與計劃彙總檢查是否每個角色屬於某個用戶。

SELECT t1.plan_id 
FROM rms.plan_role t1 
LEFT JOIN rms.user_role t2 
    ON t1.role_id = t2.role_id AND 
     t2.user_id = 100 
GROUP BY t1.plan_id 
HAVING SUM(CASE WHEN t2.id IS NULL THEN 1 ELSE 0 END) = 0 

演示在這裏:

SQLFiddle

(在MySQL中所示的演示,雖然語法在Postgres的幾乎相同,除了可能的表名)

+0

我在原文中有點困惑 - 我已經更新了它。對於那個很抱歉!基本上,我需要所有的plan_id,以使得給定的user_id的role_id集合_is是plan_ids的role_id集合的超集。 – Tyson

+0

該查詢返回user_id 100的plan_id 1,2和4.但是,plan_id 1具有用戶不具有的role_id 30。因此,計劃1的角色不是用戶角色的子集。 – Tyson

+0

@Tyson查詢似乎現在正在工作。 –

0

這種類型的查詢聽起來像existsin

select distinct pr.plan_id 
from plan_role pr 
where pr.role_id in (select ur.role_id 
        from user_role ur 
        where ur.user_id = 200 
        ); 

這將返回有一個角色莎爾所有計劃編輯與用戶200.

+0

的SQL我沒有描述我的問題不夠準確並更新了問題文本(對不起這一點!)。我需要所有的plan_id,使得給定的user_id的role_ids集合是對plan_id的role_id集合的超集。 – Tyson

1

這是通過查找用戶與缺少的角色,然後使用該設置給出最終結果。

select user_plans.* from 
(
    -- all users with all plans 
    select distinct user_id, plan_id from user_role, plan_role 
) user_plans 
left join 
(
    select user_plans_roles.plan_id, user_plans_roles.user_id from (
     -- get the result assuming user has all plans and roles 
     select distinct plan_id, user_id, plan_role.role_id 
     from plan_role, user_role 
    ) user_plans_roles 
    left join user_role users 
    on user_plans_roles.user_id = users.user_id 
    and user_plans_roles.role_id = users.role_id 
    -- exclude users without a matching role_id 
    where users.user_id is null 
) missing_user_plan_roles 
on user_plans.user_id = missing_user_plan_roles.user_id 
and user_plans.plan_id = missing_user_plan_roles.plan_id 
-- exclude missing roles 
where missing_user_plan_roles.user_id is null 
order by user_id, plan_id 

- 結果

user_id plan_id 
100 2 
100 4 
200 1 
200 2 
200 3 
200 4 

找到用戶缺少計劃的角色

select user_plans_roles.plan_id, user_plans_roles.user_id from (
    -- get the result assuming user has all plans and roles 
    select distinct plan_id, user_id, plan_role.role_id 
    from plan_role, user_role 
) user_plans_roles 
left join user_role users 
on user_plans_roles.user_id = users.user_id 
and user_plans_roles.role_id = users.role_id 
-- exclude users without a matching role_id 
where users.user_id is null 

回報

plan_id user_id 
1 100 
3 100 
相關問題