【问题标题】:MySQL left join: null elements be filtered by whereMySQL左连接:空元素由where过滤
【发布时间】:2018-11-08 06:59:18
【问题描述】:

我有 2 个 MySQL 表:join_test_ljoin_test_r

join_test_l:

+------+------+
| ca   | cb   |
+------+------+
| a    | s    |
| b    | s    |
| c    | d    |
| d    | NULL |
+------+------+

join_test_r:

+------+------+
| cc   | cb   |
+------+------+
| a    | NULL |
| b    | s    |
| c    | d    |
| d    | NULL |
+------+------+

当我尝试使用左连接和左表上的<> 过滤器进行查询时:

select * from join_test_l as l left join join_test_r as r on l.cb=r.cb where l.ca<>'c';
+------+------+------+------+
| ca   | cb   | cc   | cb   |
+------+------+------+------+
| a    | s    | b    | s    |
| b    | s    | b    | s    |
| d    | NULL | NULL | NULL |
+------+------+------+------+

l.canull 的行仍然存在。 当我尝试使用左连接和右表上的&lt;&gt; 过滤器进行查询时:

select * from join_test_l as l left join join_test_r as r on l.cb=r.cb where r.cc<>'c';
+------+------+------+------+
| ca   | cb   | cc   | cb   |
+------+------+------+------+
| a    | s    | b    | s    |
| b    | s    | b    | s    |
+------+------+------+------+

r.ccnull 的所有行也会被删除。

谁能解释一下? 我的意思是为什么结果集中的空值会被&lt;&gt; 子句过滤?

【问题讨论】:

  • 嗨。这是一个常见问题解答。请始终在谷歌上搜索您的问题/问题/目标的许多清晰、简洁和特定的版本/措辞,带和不带您的特定字符串/名称,并阅读许多答案。将您发现的相关关键字添加到搜索中。如果您没有找到答案,请发布,使用 1 个变体搜索作为标签的标题和关键字。请参阅向下投票箭头鼠标悬停文本。如果您确实有要发布的非重复代码问题,请阅读并采取行动minimal reproducible example
  • A minimal reproducible example 包括 DBMS、版本、清晰的规范、剪切、粘贴和可运行代码(包括输入)(表格初始化格式化为表格)和可区分(因此有序)所需的输出。但是调试的绝对基础说:表明你的程序在通过(子)表达式时做了你期望的事情,说明它是什么,并表明它实际上是通过增量输出做到的。研究(在手册和网络中)最少的附加代码,给出您无法解决的问题。重复,最小化工作代码。然后询问工作示例和问题示例之间的(小)差异。
  • NULL 没有价值,它是“不确定的”,因此它不能等于任何东西,甚至等于另一个 NULL(因为两者都是不确定的,你无法知道它们是否相同或不)。因此对于 NULL,您无法确定相等,因此您也无法确定 not 相等。这是 SQL 中常见的挫败感。考虑空值时必须使用ISIS NULLIS NOT NULL

标签: mysql join where


【解决方案1】:

回复&lt;&gt; & null

x&lt;&gt;ytruex 不等于(在正常意义上)y and x is not null and y is not null。当x 等于(在正常意义上)yand x is not null and y is not null 时,它是false。否则在技术上它是unknown,但它恰好被运算符/语法视为null,如is

大多数 SQL 运算符都是这样的——它们在每个参数 is not null 时返回它们的正常结果,否则 unknown(像 null 一样处理)。 SQL 运算符不是同名的普通关系或数学运算符;他们特别对待(值)unknown & null。 (说null 不是一个值是模糊无益的 SQL 文化修辞。)

关于“正常意义上的平等”,来自the MySQL 8.0 Reference Manual 12.3.2 Comparison Functions and Operators

比较运算的结果为1 (TRUE)、0 (FALSE) 或NULL

  • &lt;=&gt;

    NULL-safe 相等。此运算符执行类似于= 运算符的相等比较,但如果两个操作数都是NULL,则返回1 而不是NULL,如果一个操作数是NULL,则返回0 而不是NULL。 &lt;=&gt; 运算符等效于标准 SQL IS NOT DISTINCT FROM 运算符。

注意onwhere 返回条件计算结果为true 的行。当约束不评估为 false 时,约束得到满足。

回复left joinon & where

了解 LEFT/RIGHT JOIN 返回的内容:INNER JOIN 行加上由 NULL 扩展的不匹配的左/右表行。 FULL JOIN 返回由 NULL 扩展的 INNER JOIN 行 UNION ALL 不匹配的左右表行。作为 OUTER JOIN 的一部分,始终知道您想要什么 INNER JOIN。在 OUTER JOIN ON 删除任何由 NULL 扩展的行(即只留下 INNER JOIN 行,即“将 OUTER JOIN 变为 INNER JOIN”之后,需要可能 NULL 扩展的列不为 NULL 的 WHERE 或 ON。你有那个。

阅读您的 SQL DBMS 文档。

【讨论】:

  • 好答案;您可能还会提到 MySQL 中的空安全运算符 &lt;=&gt;。 +1
  • 采纳你的建议。
【解决方案2】:

您需要将WHERE子句中的逻辑移动到ON子句中:

SELECT *
FROM join_test_l as l
LEFT JOIN join_test_r as r
    ON l.cb = r.cb AND r.cc <> 'c';

这里的问题是WHERE 正在从结果集中过滤掉记录。另一方面,通过将逻辑移动到连接,我们保留了左表join_test_l 中的每条记录。然后,没有加入任何东西的记录将在join_test_r 中的每一列都有null

【讨论】:

  • 谢谢蒂姆,这种过滤在某些情况下有效,但我仍然想知道为什么结果集中的null 值会被&lt;&gt; 子句过滤。
猜你喜欢
  • 2012-04-15
  • 1970-01-01
  • 1970-01-01
  • 2011-02-23
  • 2011-02-01
  • 2013-01-19
  • 2022-08-24
  • 1970-01-01
  • 2019-07-16
相关资源
最近更新 更多