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

dou*_*ack 3 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'
Run Code Online (Sandbox Code Playgroud)

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

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

我究竟做错了什么?

xQb*_*ert 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'
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

  • 我个人建议不要使用第二个选项,除非`recipe_qa.type`是一个NOT NULL列(或`type`of null没有语义含义). (2认同)