为什么 NULL 永远不会将 False 与 SQL 中的任何内容进行比较


SQL 初学者最常见的问题之一是为什么子句中的NULL值“不起作用” WHERE。在本文中,我将以一种我希望有意义且易于记忆的方式对其进行解释。

如果您是 SQL 的新手并且很难理解本文,我鼓励您继续对它感到困惑,直到亮起为止。我自己必须这样做(而且我不得不认真考虑才能写这篇文章),而且我看到很多人学习 SQL。NULLs似乎总是一个重要的症结。

无法正常工作的查询 以下是两个不起作用的常见查询:

select * from table where column = null;

select * from table where column <> null;

他们都没有返回任何行!无数 SQL 老手试图向初学者解释这一点。初学者通常认为第一行应该返回行 where c1is NULL。然后这位老将指出,这NULL永远不等于任何东西。初学者然后想,“如果NULL不等于任何东西,那么' WHERE COLUMN IS NOT EQUAL TO NULL'总是为真,所以第二个查询应该返回所有结果!” 第二个WHERE子句与第一个在逻辑上相反,对吗?正确的?可悲的是,不,不是。

真正的问题:语言陷阱 初学者陷入了语言陷阱,有经验的程序员可能会说“NULL永远不等于任何东西”。这种说法似乎在暗示“NULL是不等于”。不幸的是,这是错误的。不仅是NULL不是无所不能的,它也没有不平等的任何东西。这就是语言令人困惑的地方。

事实是,在讨论NULLs时说任何带有“相等”或“不相等”字样的东西都是一个陷阱,因为没有等于或不等式、大于或小于NULLs 的概念。相反,在讨论NULLs时,人们只能说“是”或“不是”(没有“相等”一词)。

正确的思考方式 NULL 正确的理解方式NULL是它不是一个值。不是“这是一个NULL价值”,而是“这NULL不是一个价值”。一切要么是一个值,要么不是。当某物是值时,它是“1”或“你好”或“绿色”或“$5.00”等——但当某物不是值时,它根本就不是任何东西。SQL 用特殊的 non-value 表示“this has no value” NULL。当有人说“NULL价值”时,人们应该在精神上不同意,因为没有这样的东西。NULL是完全没有任何价值。

当您将一个值与 进行比较时,您会得到什么NULL? 简答:NULL。每次。将任何东西与进行比较的结果NULL,甚至是它本身,总是、总是NULL。与 的比较NULL永远不会是真或假。由于NULL永远不可能等于任何值,因此它也永远不可能不相等。

有时人们很难理解为什么与 的比较NULL永远不会是真或假。这是一个可能有帮助的非正式证明:

鉴于以下谓词,

NULL 不是一个值 任何值都不可能等于非值 下面是反证法:假设一个NULL不等于一个值的时刻——比如说一个实数,不包括无穷大和负无穷大。我会选择一个示例数字,比如 5。

假设NULL <> 5. 也就是说,NULL <> 5是一个真表达式(比较运算是布尔值、真或假)。 这意味着“ NULL < 5 or NULL > 5”是真的,因为我处理的是有限的实数;如果不相等,则必须更大或更小。 因此,存在一个实数等于NULL; 它要么小于 5,要么大于 5。 这是一个矛盾,因为我认为没有任何值可以等于NULL。 因此NULL既不等于一个值也不等于它,所以任何涉及的NULL比较既不是 true 也不是 false。涉及的比较结果NULL不是布尔值——它是一个非值。你只是无法将存在的东西与不存在的东西进行比较。

必须这样,因为如果与非值的比较具有定义的值,则每个查询都可能被重写以返回错误的结果。可以将表达式转换为给出相反答案的等效表达式,等等。

编写查询的正确方法 这些查询必须使用特殊的比较运算符编写,而不是使用布尔比较运算符,例如小于和大于、等于和不等于IS NULL:

select * from table where column is null;

select * from table where column is not null;

该IS NULL运算符测试一个值是否为空或不为空,并返回一个布尔值。

事实是,我撒了谎 我试图写这篇文章来帮助人们理解非值在查询中的工作原理,所以我对事实很慷慨。

由于计算机只处理存在的东西,不存在是不可能的,所以NULLs 必须在内部实现为某个值,在某处——即使它是一个表明另一个值不是一个值的值(哈?)。

我NULL也在掩盖一些关于与 比较的事情。NULLs 结果为三值逻辑;布尔值不再只是TRUEand FALSE,也可以是UNKNOWN。比较NULLs的结果是UNKNOWN,这与 不是一回事NULL,但这只是语义差异和深入的数学思考,不会对您如何编写查询产生实质性影响。

例如,MySQL 实现了UNKNOWNas NULL,尽管它并不完全一致——请尝试以下查询:

select unknown;
select null;
select true;
select false;
select null is unknown;
select false is null;
select true is null;
select unknown is null;

请记住,NULL它既不等于也不等于任何事物,我保证您将永远安全。对NULLvsUNKNOWN和所有这些的优点非常挑剔是没有用的。

一个益智游戏 COUNT 有人在 MySQL 手册页上发表了关于GROUP BY 子句扩展的评论,我认为在这里讨论很有趣。查询是一种计算组内子集的方法:

select shoeStyle,
   count(color) as Count,
   count(color = 'red' OR NULL) as redCount,
   count(color = 'green' OR NULL) as greenCount,
   count(color = 'blue' OR NULL) as blueCount
from bowlingShoes
group by shoeStyle;

评论的作者说“OR NULL是必要的,否则你只会得到组中所有行的计数。” 为什么是这样?

如果OR NULL省略 ,则表达式的结果是布尔值TRUE或FALSE,它们是实际值。该COUNT函数计算任何存在的值,而不是某物是否为TRUE或FALSE,因此查询行为正确。

另一方面,表达式的结果color = 'green' OR NULL是TRUEor NULL。布尔表达式在计算时会短路。只要逻辑OR表达式中的第一个子表达式为真,整个结果就为真,因此当颜色为绿色时,表达式TRUE立即是一个COUNT-able 值。如果颜色不是绿色,则表达式变为FALSE OR NULL,NULL当然,这不是COUNT-able 值。

您可以通过以下查询看到这一点:

mysql> select true or null;
+--------------+
| true or null |
+--------------+
| 1            |
+--------------+
1 row in set (0.00 sec)

mysql> select false or null;
+---------------+
| false or null |
+---------------+
| NULL          |
+---------------+
1 row in set (0.00 sec)


原文链接:https://codingdict.com/