多对多名称和角色表 -
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中实现这一点?
答案 0 :(得分:2)
假设您只有此表,您可以使用:
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
);
<强> Example on SQL Fiddle 强>
主查询将生成所有名称/角色对,然后not exists将释放已存在的所有对。
如果您确实有名称和角色表,那么您可以使用实际表替换子查询:
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
will perform better than 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而没有which is not a good idea at all
答案 1 :(得分:2)
获得某人没有的角色有点复杂。您必须生成所有名称和角色对,然后选择不存在的名称和角色。这使用左外连接。
以下是执行此操作的标准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()
而没有长度。默认值可能无法达到预期效果。