[英]SQL: Selecting rows whose distinct values are a subset of another table's distinct values
給出以下表格:
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
什么是將返回所有plan_ids的SQL查詢,以便給定的user_id的role_ids集合是plan_ids的role_ids集合的超集?
換句話說,我如何找到給定用戶的計划,以便用戶至少與每個計划共享所有角色。
例如, user_id
100應返回plan_id
s 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);
我會在這里使用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
在這里演示:
(在MySQL中顯示的演示,雖然Postgres中的語法幾乎相同,但可能用於表名)
這通過查找缺少角色的用戶然后使用該集合來給出最終結果來工作。
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
用於查找缺少計划角色的用戶的SQL
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
這種類型的查詢聽起來像exists
或in
:
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共享的角色的所有計划。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.