MySQL左连接:null元素按位置过滤

时间:2018-11-08 06:59:18

标签: mysql join where

我有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的行。 当我尝试使用左联接和右表上的<>过滤器进行查询时:

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的所有行也被删除。

能解释一下吗? 我的意思是为什么结果集中的空值被<>子句过滤?

2 个答案:

答案 0 :(得分:2)

关于<>null

x<>ytrue x不相等时(通常意义上),

yand x is not null and y is not null。当false等于(在正常意义上)等于x y时为and x is not null and y is not null。否则,从技术上讲,它是unknown,但是碰巧像null这样的运算符/语法将其视为is

大多数SQL运算符都是这样的-当每个参数is not null和其他参数unknown(与null一样对待时,它们返回其正常结果。 SQL运算符不是具有相同名称的普通关系或数学运算符;他们特别对待unknownnull(值)。 (说null不是一个值是模糊无助的SQL文化言论。)

来自the MySQL 8.0 Reference Manual 12.3.2 Comparison Functions and Operators的“正常的平等感”:

  

比较操作得出的值为1TRUE),0FALSE)或NULL

  
      
  • <=>

         

    NULL-相等。该运算符执行类似于=运算符的相等比较,但是如果两个操作数均为1,则返回NULL而不是NULL,如果返回两个,则返回0而不是NULL操作数为NULL<=>运算符等效于标准SQL IS NOT DISTINCT FROM运算符。

  •   

注释onwhere返回条件评估为true的行。当约束的评估结果不为false时,这些约束就会满足。

关于left join onwhere

了解LEFT / RIGHT JOIN返回的内容:INNER JOIN行以及不匹配的左/右表行,这些行由NULL扩展。 FULL JOIN返回INNER JOIN行UNION ALL,所有不匹配的左右表行扩展为NULL。始终知道您要作为OUTER JOIN的一部分的INNER JOIN。在WHERE或ON上,在OUTER JOIN ON上需要一个可能为NULL扩展的列不为NULL的情况下,删除所有扩展为NULL的行,即仅保留INNER JOIN行,即“将OUTER JOIN转换为INNER JOIN”。你有那个。

阅读您的SQL DBMS文档。

答案 1 :(得分:1)

您需要将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中。然后,未连接任何记录的记录在null中的每一列中将有join_test_r