繁体   English   中英

SQL自联接,不存在或其他?

[英]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
        );

SQL小提琴示例

主查询将生成所有名称/角色对,然后不存在将排除所有已存在的对。

如果实际上有一个名称和角色表,则可以用实际表替换子查询:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM