与内连接相反

Posted

技术标签:

【中文标题】与内连接相反【英文标题】:Opposite of inner join 【发布时间】:2011-03-26 03:50:16 【问题描述】:

内连接的反面是什么?对于表 Person (int PersonId, varchar PersoName, int AddrId),我想知道在 Person with bad AddrId 中没有在 Address 表中的行。

【问题讨论】:

【参考方案1】:

内连接与外连接不同。它们服务于不同的目的。但是,从一个表中查找另一个表中不存在的行的常见模式是使用外连接:

Select ...
From Table1
    Left Join Table2
        On Table2.ForeignKeyCol = Table1.PrimaryKeyCol
Where Table2.PrimaryKeyCol Is Null

这将返回 Table1 中的所有行和 Table2 中的任何匹配行,这样如果给定的 Table1 行没有 Table2 匹配,则返回 Table2 列的空值。然后要求不可为空的列 (Table2.PrimaryKeyCol) 为 Null,我将从 Table1 中获取 Table2 中不存在的所有行。使用您的示例表名,我们将有如下内容:

Select ...
From Person
    Left Join Address
        On Address.PersonId = Person.Id
Where Address.Id Is Null

【讨论】:

【参考方案2】:

内连接的反面是什么?

一个 OUTER join,可以是三个选项:

左 正确 已满

This is a good visual representation of JOINs

我想知道地址表中没有行的 Person with bad AddrId 中的行。

使用 LEFT JOIN/IS NULL

   SELECT p.*
     FROM PERSON p
LEFT JOIN ADDRESS a ON a.addrid = p.addrid
    WHERE a.addrid IS NULL

使用不存在

SELECT p.*
  FROM PERSON p
 WHERE NOT EXISTS(SELECT NULL
                    FROM ADDRESS a
                   WHERE a.addrid = p.addrid)

使用 NOT IN

SELECT p.*
  FROM PERSON p
 WHERE p.addrid NOT IN (SELECT a.addrid
                          FROM ADDRESS a)

【讨论】:

+1 以完整地回答如何在具有错误 AddrId 的 Person 中查找行。 OTOH,我不认为外部联接是 相反 内部联接。只是不同。 @Shannon Severance:同意 - 这就是我投票支持 Thomas 答案的原因。 +1 呵呵。我认为您应该对精美的格式、完整性和 Jeff 的精美维恩图表示赞同。 这是一个很好的回应,我唯一要补充的(正如我在不太全面的回应中所尝试的那样:-P)是这些方法对 Left Join / IS NULL 有不同的性能影响最快的假设你正在加入索引列。 @Zugwalt:谢谢,但是LEFT JOIN/IS NULL is the fastest only on mysql, assuming the columns can't be NULL。任何其他数据库都不是这种情况。【参考方案3】:

我认为最好的解决方案是使用EXISTS。像这样:

SELECT * FROM Person P
WHERE P.AddrId IS NOT NULL 
  AND NOT EXISTS ( SELECT 1 FROM Address A WHERE A.AddrId = P.AddrId )

上面的查询将返回每个设置了 AddrId 但在 Address 表中没有对应记录的人。

Obs.:EXISTS查询中使用常量1来避免表访问。

【讨论】:

【参考方案4】:

如果您将内连接视为满足特定条件的两个表的行,那么相反的情况是 either 表中不满足特定条件的行。

例如,以下将选择地址表中具有地址的所有人员:

SELECT p.PersonName, a.Address
FROM people p
JOIN addresses a
    ON p.addressId = a.addressId

我想与此“相反”的做法是选择所有没有地址的人和所有没有人的地址。但是,这似乎不是您要问的,您似乎只对其中的一个组成部分感兴趣:地址表中没有地址的所有人。

为此,最好使用左连接:

SELECT p.PersonName
FROM people p
LEFT JOIN addresses a
   ON p.addressId = a.addressId
WHERE a.addressId IS NULL

请注意,通常有些人更喜欢以不同的方式编写它,因为他们认为它更具可读性(但是根据我使用大型表的经验,它的性能比上述方式差):

SELECT PersonName
FROM people
WHERE addressId NOT IN (SELECT addressId FROM addresses)

【讨论】:

由于我的原因,您 LEFT JOIN 使我的查询崩溃导致 tmp 文件夹中没有可用空间。最后一个用 NOT EXISTS 替换 NOT IN 的解决方案可以正常工作。

以上是关于与内连接相反的主要内容,如果未能解决你的问题,请参考以下文章

关于与内连接结合使用时的外连接

多表查询与内连接,外连接

SQL中外连接与内连接之间的区别

左连接与右连接,外连接与内连接

SQL 中 3 个条件的联合与内连接

MySQL 的内连接、左连接、右连接有啥区别?