【问题标题】:Why does a SQL query with != 0 not include NULL values?为什么带有 != 0 的 SQL 查询不包含 NULL 值?
【发布时间】:2016-03-10 16:31:29
【问题描述】:

这是两个测试表的 sqlfiddle:http://sqlfiddle.com/#!9/33361/3

tl;dr:为什么带有 != 0 的 SQL 查询不包含 NULL 值?

我正在左连接这两个表。我想查看在tableB.field1 中具有NULL 或在tableB.field1 中具有1 的行,但排除所有在tableB.field1 中具有0 的行。

我认为这个查询(示例 6)应该给我这个结果,但它没有得到空记录。

SELECT * FROM tableA a
LEFT JOIN tableB b ON a.id = b.join_id
WHERE
b.field1 != 0;

我必须使用这个更长的查询(示例 4):

SELECT * FROM tableA a
LEFT JOIN tableB b ON a.id = b.join_id
WHERE
b.field1 != 0 OR b.field1 IS NULL;

只是好奇——MySQL 怎么不认为 N​​ULL 是 != 0?

当我将条件移动到 ON 子句时,我得到了一个意外的行:

mysql> SELECT * FROM tableA a
    -> LEFT JOIN tableB b ON a.id = b.join_id AND b.field1 != 0;
+------+--------+--------+---------+--------+--------+
| id   | field1 | field2 | join_id | field1 | field2 |
+------+--------+--------+---------+--------+--------+
|    1 | testA1 | testA1 |       1 | 1      | testB1 |
|    2 | testA2 | testA2 |    NULL | NULL   | NULL   |
|    3 | testA3 | testA3 |    NULL | NULL   | NULL   |
+------+--------+--------+---------+--------+--------+
3 rows in set (0.00 sec)

【问题讨论】:

  • 第一个例子是否定outer join——您可以将该条件移至on,它应该可以在没有null检查的情况下正常工作。

标签: mysql null comparison sqlfiddle


【解决方案1】:

为什么带有 != 0 的 SQL 查询不包含 NULL 值?

简答:因为SELECT 0 != NULL 返回(NULL)

更长的答案:根据MySQL's documentation

您不能使用算术比较运算符(例如 =、)来测试 NULL。

如果您想在 Select 子句中包含 NULL,则必须借助“IS NULL”或“IFNULL”将其转换为算术表示。

您的 SQL 查询可以重写为:

SELECT * 
FROM tableA a
LEFT JOIN tableB b ON a.id = b.join_id
WHERE
    IFNULL(b.field1, -1) != 0;

【讨论】:

  • 或者只使用 MySQL 的 NULL-safe 相等比较运算符,<=>——例如WHERE NOT b.field1 <=> 0.
【解决方案2】:

From eggyal's comment: “或者只使用 MySQL 的 NULL 安全相等比较运算符,<=> —例如 WHERE NOT b.field1 &lt;=&gt; 0。”

SELECT * FROM tableA a
LEFT JOIN tableB b ON a.id = b.join_id
WHERE NOT b.field1 <=> 0
;

【讨论】:

    【解决方案3】:

    使用外连接时,SQL 引擎使用空值表示组合集中没有数据。针对 null 值的相等性检查总是返回 false。

    考虑:如果 null = null then 1 else 0 end 这将始终产生 0!

    您问:为什么带有 != 0 的 SQL 查询不包含 NULL 值?

    在您的查询中,在引擎生成连接数据集之后应用 where 子句。
    假设 A 的 ID 为 1,2,而 B 只有 1。

    左连接的结果集将没有 where 子句:

      A.ID B.ID
        1  1
        2  NULL
    

    你的 where 子句被应用 b.field !=0

    你会得到

      A.ID B.ID
        1  1
    

    Null 相等检查的结果始终为 FALSE,因此第 2 行被排除,第 1 行被保留。

    如果您将过滤器移至联接条件,则在联接表之前应用限制。

    SELECT * FROM tableA a
    LEFT JOIN tableB b 
       ON a.id = b.join_id
      and b.field1 != 0;
    
      A.ID B.ID
        1  1
        2  NULL
    

    并且由于第 2 行在 B 中没有记录,因此您会得到两行。

    MySQL 怎么不认为 N​​ULL 是 != 0?

    Null 是一种特殊情况。与 null 的相等比较总是会产生错误。

    is nullis not null 是可用于检查值是否为空的两种方法。

    您也可以使用where coalesce(b.field1,1) != 0 来确保返回第二条记录。尽管您最好将左连接中第二个表上的任何过滤器简单地移动到连接条件。

    【讨论】:

    • 严格正确—涉及NULL的比较产生NULL,而不是FALSE
    • select case when null = null then 1 when null &lt;&gt; null then 0 else -1 end 好点!
    • 我希望我能接受两者。感谢您的深入回答。
    猜你喜欢
    • 2017-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-04
    • 2015-01-10
    • 1970-01-01
    • 2014-11-14
    相关资源
    最近更新 更多