[英]SQL Self-join, Not Exists, Or Something Else?
多对多名称和角色表-
create table t (name varchar, role varchar) ;
insert into t (name, role) values ('joe', 'husband'), ('joe', 'father'),
('tom', 'husband'), ('neo', 'bachelor') ;
> select * from t;
name | role
------+----------
joe | husband
joe | father
tom | husband
neo | bachelor
需要转换为名字的映射和角色他(她) 不具备-
not_a | name
---------+-----------
husband | neo
father | tom
father | neo
bachelor | joe
bachelor | tom
如何在不迭代每个角色/名称的情况下在真正的SQL中实现该目标?
假设您只有此表,则可以使用:
SELECT r.role AS not_a, n.Name
FROM (SELECT DISTINCT Name FROM T) AS n
CROSS JOIN (SELECT DISTINCT Role FROM T) AS r
WHERE NOT EXISTS
( SELECT 1
FROM t
WHERE t.Name = n.Name
AND t.Role = r.Role
);
主查询将生成所有名称/角色对,然后不存在将排除所有已存在的对。
如果实际上有一个名称和角色表,则可以用实际表替换子查询:
SELECT r.role AS not_a, n.Name
FROM Names AS n
CROSS JOIN Roles AS r
WHERE NOT EXISTS
( SELECT 1
FROM t
WHERE t.Name = n.Name
AND t.Role = r.Role
);
您尚未指定DBMS,因此,如果您使用的是MySQL,则使用LEFT JOIN\\IS NULL
将优于NOT EXISTS
SELECT r.role AS not_a, n.Name
FROM (SELECT DISTINCT Name FROM T) AS n
CROSS JOIN (SELECT DISTINCT Role FROM T) AS r
LEFT JOIN t
ON t.Name = n.Name
AND t.Role = r.Role
WHERE t.Name IS NULL;
我还假设这只是一个演示,但是在您的表DDL中,您使用的VARCHAR没有长度,这根本不是一个好主意
获得某人没有的角色有点复杂。 您必须生成所有成对的名称和角色,然后挑选出不存在的名称和角色。 这使用左外部联接。
以下是执行此操作的标准SQL:
select r.role as not_a, n.name
from (select distinct name from t) n cross join
(select distinct role from t) r left outer join
t
on t.name = n.name and t.role = r.role
where t.name is null;
注意:定义变量和列时, 切勿使用没有长度的varchar()
。 默认值可能无法满足您的期望。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.