如何解释左连接/是否为空并且不存在,它们之间有什么区别?

时间:2015-05-07 05:38:56

标签: mysql sql sql-server

昨天,在调试其他开发人员代码时,我遇到了以下查询(将此查询称为Q1)

select b.id from b left join a on b.a_id = a.id where a.id is null

表a有一个字段:

id        primary key

表b有两个字段:

id        primary key
a_id      foreign key (reference a.id)

当我跑到查询(Q1)之上时,它给了我结果:所有b.id,其中b.a_id在a.id中不可用

但我不明白上面的查询(Q1),特别是“where”子句。如果我们检查a.id是否为空,那么它如何匹配以找到b表中不可用的那些。

此外,Q1和Q2(查询下方)之间有什么区别:

select b.id from b where not exists (select * from a where a.id = b.a_id)

我甚至不理解Q2。

3 个答案:

答案 0 :(得分:1)

Q1中的关键点是left join。你可能知道 LEFT JOIN关键字返回左表(Customers)中的所有行,即使右表(Orders)中没有匹配项也是如此。 旁注:正如您所提到的,id是表a的主键,所以它不是null,而where子句永远不会是真的! 在Q2中,您只选择那些在表a中具有相应值的记录。 您可以找到更多信息here

答案 1 :(得分:1)

第一个查询,Q1:

我相信你会再次看到这一点,这并不罕见。 left join将获取左表中的所有记录,以及右侧与参考相匹配的记录。但是where子句正在做的是将其反转,以便它只选择匹配的位置,即a.id is null

您可以将其放在更具描述性的文字中:

  • 从表 b
  • 中获取所有行
  • 从表 a 中获取所有匹配的行(基于PK-> FK)
  • 现在只选择 b a
  • 中没有匹配的记录

第二个查询Q2 会给你相同的结果,但这是另一种写作方式。基本上是这样的:

  • 从表 b
  • 中获取所有行
  • 现在只选择 b 中的记录,其中 a 中没有匹配的记录(不存在)

关于两个查询的效果,您可以read more here。它基本上归结为“它取决于”。通常情况下,exists会有非常好的表现,但由于我们在前面添加not,因此仍然需要检查每条记录。

编辑:
关于这些查询有一个很好的写作,还有一些其他的编写方法,在这里:What's the difference between NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULL?

答案 2 :(得分:1)

线程步骤

第一

select b.id from b

这很简单,结果就是表b中的所有行。

第二

select b.id from b left join a on b.a_id = a.id

请注意,由于left join,此结果中的记录数与第一步相同。要了解left join,您可以尝试inner join

select b.id from b inner join a on b.a_id = a.id

行数应该更少,因为inner join只返回来自表b并加入a的行。因此a_id不在表a中的记录将不会显示。 但是离开加入不要这样做!左连接将显示表b中的所有记录,即使它不存在于表a中的记录,并且无法与表a连接的记录将保留为空

这就是为什么会出现第三步的原因

添加空检查条件

select b.id from b left join a on b.a_id = a.id where a.id is null