MySQL左连接不返回连接表的空值

Posted

技术标签:

【中文标题】MySQL左连接不返回连接表的空值【英文标题】:MySQL Left Join not returning null values for joined table 【发布时间】:2011-07-22 12:22:14 【问题描述】:

请帮助我完成以下 mysql 查询,它连接两个表(A 和 B):

SELECT * from A
left join B on A.sid = B.sid
where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5)
AND (rYear = 2011 or rYear is null)

roleCode 是表 A 中的一个字段,rYear 是表 B 中的一个字段

结果集与预期不符。只返回了 185 行,但是表 A 中有 629 行符合 where 条件。表 B 中没有匹配行的行不应该返回其 B 字段的空值吗?

【问题讨论】:

1859 行,rCode 在 (1,2,3,5) 中? 是的,问题不在于你的加入,摆脱它,看看结果如何。 抱歉 - 表 A 中有 629 行符合 where 条件。 你的逻辑有缺陷,结果与你所说的不正确。语句的 AND 部分可以有效地返回 0 个结果。如果行连接并且它的值不是 2011,它将不匹配。因此,您的查询可能是完全正确的,并且不会返回与第一个 WHERE 条件匹配的所有结果 @nate 解释错误。看我的回答 【参考方案1】:

您不应在 WHERE 子句中指定 rYear。这些限制了您加入后的结果。您应该在 ON 子句中指定 rYear 以从表 B 中获取 NULL 记录。

SELECT * from A
left join B 
on A.sid = B.sid 
AND (rYear = 2011 or rYear is null)
where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5)

【讨论】:

嗨,杰格。这很好用!但是,我是否误解了 MySQL 文档? SQL Server 将为原始查询返回大量空值。 dev.mysql.com/doc/refman/5.0/en/left-join-optimization.html - 特别是:“如果 A 中有一行与 WHERE 子句匹配,但 B 中没有一行与 ON 条件匹配,则会生成一个额外的 B 行,所有列都设置为 NULL。” JOIN 条件中不需要 rYear IS NULL。使用ON a.sid = b.sid AND rYear = 2011 就足够了 @a_h // 没有解释为什么 WHERE .. (OR rYear IS NULL) 不起作用?有什么想法吗?事实上,如果 rYear 可以为空,Jage 的查询和您的建议会返回不同的数据 @Richard:是的,你是对的。我有点太快了。当然,它有所作为。对不起(也对 Jage)【参考方案2】:

Greg,这真的是查询的全部内容吗?

示例表

create table A(rCode int, sid int);
insert A select 1,1;
insert A select 2,3;
insert A select 3,2;
insert A select 5,4;
insert A select 1,5;
create table B(rYear int, sid int);
insert B select 2011,1;
insert B select null,3;
insert B select 2011,2;
insert B select 2015,2;

查询:

SELECT * from A
left join B on A.sid = B.sid
where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5)
AND (rYear = 2011 or rYear is null);

SELECT * from A
left join B on A.sid = B.sid AND (rYear = 2011 or rYear is null)
where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5);

两个查询完全相同,都返回:

rCode       sid         rYear       sid
----------- ----------- ----------- -----------
1           1           2011        1
2           3           NULL        3
3           2           2011        2
5           4           NULL        NULL
1           5           NULL        NULL

所以我很惊讶 Jage 的查询(第二个选项)对您有效,但对您的原始查询无效。如果没有内在的or rYear is null,情况就会不同。

这样想 LEFT JOIN [1]

SELECT * from A
left join B on A.sid = B.sid

将所有内容保留在 A 中,如果在 ON 子句中匹配,则保留 B,否则用 NULL 填充 B 列。添加 WHERE 子句 [2]

where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5)
AND (rYear = 2011 or rYear is null);

使用 [1] 的输出,根据过滤器进行 CUT,在左连接之后应用。使用rYear is null,它仍应保留所有 A 记录,条件是匹配 rCode 过滤器。但是,如果 rYear 中的过滤器只有

AND (rYear in (2011,2012))

这是一个不同的故事,因为在 B 不匹配的地方,rYear 用 NULL 填充,这与 rYear 过滤器不匹配 -> 整行被删除,包括 A 记录。 rYear 上的此类过滤器将进入 ON 子句,如下所示,否则不妨将其设为 INNER JOIN。

SELECT * from A
left join B on A.sid = B.sid AND (rYear in (2011,2012))
where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5)

【讨论】:

真的很有帮助,理查德谢谢你。表中还有其他几个字段,查询要大得多,但我在尝试解决问题时减少了查询,但也因此在这里更容易阅读。 Jage 的解决方案是我唯一可以开始工作的解决方案。如果您给我您的电子邮件,如果您有兴趣,我可以将表格的详细信息发送给您?我只在 SQL Server 中完成过左连接,这对我来说是 MySQL 中的第一次! :) @Greg 如果您在 SQL Server 中完成了它们,那么您已经在 MySQL 中完成了它们。他们是一样的。请参阅有关 ON 和 WHERE 子句差异的最后一点,它们应该可以帮助您完成。

以上是关于MySQL左连接不返回连接表的空值的主要内容,如果未能解决你的问题,请参考以下文章

MySQL--7种join连接

左外连接和右外连接的区别

mysql左连接没有数据还会查出来吗

如何为第一个表的空白或空值应用左连接?

SQL 查询数据连接具有它忽略的空值

Pyspark 数据框使用默认值左连接