在左连接中没有从表A获取所有记录

时间:2014-06-26 17:42:34

标签: mysql sql join left-join

我有一份食谱质量保证状态表,并希望选择所有“丢弃”记录,包括重叠状态的“完美”状态信息。但是,我只是得到了十字路口而且我想要所有'丢弃'的记录。

我想执行一个左连接,它会给出recipe_qa表中的所有'discard'行,并与任何'完美'行连接。

select *
from recipe_qa as bad
left join recipe_qa as good on good.id = bad.id
where bad.type = 'discard'
and good.type = 'perfect'

上面的查询返回的行中有id的“完美”和“丢弃”记录(24行)。我想要的是一个查询,它将给我所有'丢弃'行(76行),带有'完美'id或null,其中没有相应的行。

这是一个小提琴:http://sqlfiddle.com/#!2/faa49/4

我做错了什么?

1 个答案:

答案 0 :(得分:6)

使用左(或外)连接时,您必须考虑何时施加数据限制与创建笛卡尔时的时间。

假设您想要来自一个表(A)的所有记录,并且只想要在另一个表(B)中匹配的那些记录。执行连接时,B中将出现NULL值(不匹配的记录到A)。在B字段中添加限制条件(where子句)实际上会从A中删除您想要的记录;作为where子句在连接之后执行。这与您开始使用INNER JOIN的效果相同!

使用外连接时,只需将B表上的限制条件移动到连接即可避免这种情况。这样,在施加限制之后生成笛卡尔,确保表A中的“所有记录”保持所有记录。如果没有在连接上,正如您所见,限制是在笛卡尔坐标之后施加的,因此删除了空值,并且您不再获得“所有记录”,因此取消了LEFT连接。这就好像你在第一时间做INNER连接一样。这就是为什么做一个OR语句来返回空值,这个值也可以工作,但只有当它是一个NOT NULL列(或者null的类型没有语义)时,正如LC在下面的评论中指出的那样。

在这种情况下,good.type的where子句正在消除左连接的结果,因此要么在生成笛卡尔坐标之前将条件添加到强制限制的连接中(允许空值存在)

select *
from recipe_qa as bad
left join recipe_qa as good 
  on good.id = bad.id
 and good.type = 'perfect'
where bad.type = 'discard'

http://sqlfiddle.com/#!2/faa49/8/0

或使用is null条件不从左连接中排除记录。这有一些风险在以下评论中有所体现。

select *
from recipe_qa as bad
left join recipe_qa as good 
  on good.id = bad.id
where bad.type = 'discard'
 and (good.type = 'perfect' or good.type is null)