与内连接相反
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 的解决方案可以正常工作。以上是关于与内连接相反的主要内容,如果未能解决你的问题,请参考以下文章