为什么在 SQL 服务器中 NULL = NULL 计算结果为 false

在 SQL 服务器中,如果在 where 子句中有 nullParam=NULL,它总是计算为 false。这是违反直觉的,给我造成了许多错误。我的确明白 IS NULLIS NOT NULL关键字是正确的方式做到这一点。但是为什么 SQL 服务器会有这样的行为呢?

151099 次浏览

你不知道两件事是什么,并不意味着它们是相等的。如果当你想到 NULL时,你想到的是“ NULL”(字符串) ,那么你可能想要一个不同的相等性测试,比如 Postgreql 的 IS DISTINCT FROMIS NOT DISTINCT FROM

来自 PostgreSQL 文档关于 < em > “比较函数和运算符”

表达式 IS DISTINCT FROM表达式

表达式 IS NOT DISTINCT FROM表达式

对于非空输入,IS DISTINCT FROM<>运算符相同。但是,如果两个输入都为 null,则返回 false,如果只有一个输入为 null,则返回 true。类似地,对于非空输入,IS NOT DISTINCT FROM=相同,但是当两个输入都为空时返回 true,当只有一个输入为空时返回 false。因此,这些构造实际上就像 null 是一个正常的数据值,而不是“未知的”。

在这种情况下,可以将 null 看作“未知”(或者“不存在”)。在这两种情况下,你不能说它们是相等的,因为你不知道它们的价值。所以,null = null 的计算结果不是 true (false 或 null,取决于您的系统) ,因为您不知道它们是否相等。此行为在 ANSI SQL-92标准中定义。

编辑: 这取决于您的 Ansi _ null设置。如果你有 ANSI _ NULLS 关闭,这将评估为真。为一个示例运行以下代码..。

set ansi_nulls off


if null = null
print 'true'
else
print 'false'




set ansi_nulls ON


if null = null
print 'true'
else
print 'false'

也许这要视情况而定,但我认为 NULL=NULL的计算结果与大多数使用 NULL 作为操作数的操作一样,都是 NULL

NULL 不等于任何东西,甚至不等于它自己。对于理解 NULL 的行为,我个人的解决方案是尽可能避免使用它:)。

Null 在 sql 中是未知的,所以我们不能期望两个未知数是相同的。

但是您可以通过设置 ANSI _ NULLS 为 Off (默认为 On)来获得这种行为吗 您将能够对 null 使用 = 运算符

SET ANSI_NULLS off
if null=null
print 1
else
print 2
set ansi_nulls on
if null=null
print 1
else
print 2

MSDN 对 null 和它们产生的三个状态逻辑有很好的描述性 文章

简而言之,SQL92规范将 NULL 定义为未知,并且在以下操作符中使用 NULL 会给非初学者带来意想不到的结果:

= operator NULL   true   false
NULL       NULL   NULL   NULL
true       NULL   true   false
false      NULL   false  true


and op     NULL   true   false
NULL       NULL   NULL   false
true       NULL   true   false
false      false  false  false


or op      NULL   true   false
NULL       NULL   true   NULL
true       true   true   true
false      NULL   true   false

问题是:
一个未知数等于另一个未知数吗?
(NULL = NULL)
这个问题没有人能回答,所以它默认为 true 或 false,这取决于您的 ansi _ null 设置。

但问题是:
这个未知变量是未知的吗?
这个问题完全不同,可以用真实来回答。

nullVariable = null 正在比较这些值
比较变量的状态

在这里,我希望澄清我的立场。

那个 NULL = NULLFALSE的评估是错误的。黑客和先生正确地回答了 NULL。 原因如下: Dewayne Christensen 在给 Scott Ivey的评论中写道:

因为现在是十二月,我们用 季节性的例子。我有两个礼物 在树下。现在,你告诉我,如果我 不管有没有同样的东西。

它们可以是不同的,也可以是相等的,你不知道直到一个打开,两个都出现。谁知道呢?你邀请了两个互不相识的人,他们都给了你同样的礼物——罕见的,但并非不可能的 §

那么问题来了: 这两个 UNKNOWN 表示相同(相等,=)吗? 正确答案是: UNKNOWN (即 NULL)。

这个示例旨在演示“/strong >”。.(falsenull,取决于您的系统)。."是一个正确的答案-它不是,只有NULL是正确的在3VL (或是对你来说可以接受一个系统给出错误的答案?)

对这个问题的正确回答必须强调以下两点:

  • 三值逻辑(3VL)是违反直觉的(请参阅 Stackoverflow 和其他论坛上关于这个主题的无数其他问题,以确保) ;
  • 基于 SQL 的 DBMS 通常甚至不尊重3VL,它们有时会给出错误的答案(正如最初的海报断言,SQLServer 在这种情况下所做的那样)。

因此,我重申: SQL 不会强迫人们解释相等的自反性质,它表明:

for any x, x = x §§(简明英语: 无论什么话语宇宙,一个“东西”总是等于它自己)。

..在一个3VL (TRUEFALSENULL)。人们的期望值应该符合2VL (TRUEFALSE,甚至在 SQL 中对所有其他值都是有效的) ,即 x = x 总是评价为 TRUE,对任何可能的 x 值都是有效的——没有例外。

还要注意,NULL 是有效的“ 非价值观”(因为它们的辩护律师假装它们是) ,可以将其分配为属性值(? ?)作为关系变量的一部分。因此,它们是每种类型(域)的可接受值,而不仅仅是逻辑表达式的类型。

我就是这个意思: NULL,作为一个价值,是一个“奇怪的野兽”。没有委婉的说法,我更喜欢说: 胡说八道

我认为这个表述更加清楚,而且没有那么多争议——对不起,我的英语水平很差。

这只是 NULL 问题的 。如果可能的话,最好完全避免它们。

我们在这里关注的是 价值观,所以这两个呈现是 一直都是两个不同的物理对象的事实不是一个有效的反对意见,如果你不相信我很抱歉,这不是解释价值和“对象”语义之间的区别的地方(关系代数从一开始就有价值语义-参见 Codd 的信息原理,我认为一些 SQL 数据库管理系统实现甚至不关心一个常见的语义)。

据我所知,这是一个公理接受(在形式或其他,但总是在2VL 解释) ,因为古代和 没错是如此直观。3VL (实际上是一个逻辑系列)是最近才开发的(但我不确定是什么时候开发的)。

旁注: 如果有人试图引入 波顿单位选择类型来证明 SQL NULL 的合理性,我只有在经过一个相当详细的检查之后才会相信,这个检查将展示使用 NULL 的 SQL 实现是如何拥有一个健全的类型系统的,并最终澄清什么是 NULL (这些“值不完全是值”)。


在接下来的文章中,我将引用一些作者的话 可能是我的而不是原作者的

在 SQL NULLs 上的 Joe Celko

我看到 Joe Celko 经常在这个论坛上被引用。显然他在这里是个很受尊敬的作家。所以,我对自己说: “他是怎么写 SQL NULL 的?他如何解释大量的 NULL 问题?”.我的一个朋友有一个电子书版的 乔 · 塞尔科的聪明人 SQL: 高级 SQL 编程,第3版。我看看。

首先,目录。最让我震惊的是 NULL 被提到的次数,以及在各种不同的上下文中:

3.4算术和 NULL 109
3.5与 NULL 110之间的值转换
3.5.1 NULLIF ()函数110
6个 NULL: SQL 185中缺少的数据
6.4比较空位190
6.5 NULL 和逻辑190
6.5.1子查询谓词191中的 NULLS
6.5.2标准 SQL 解决方案193
6.6数学及空位193
6.7函数和 NULL 193
6.8 NULL 和主机语言194
6.9无效标准的设计建议195
6.9.1避免来自主机程序的 NULL 197
6.10关于多个 NULL 值的注释198
10.1 IS NULL 谓词241
10.1.1空位来源242
...

等等,听起来像“讨厌的特殊情况”。

我将从这本书中摘录一些案例,出于版权方面的原因,试图将自己限制在本质上。我认为这些引用属于“合理使用”原则,它们甚至可以刺激人们购买这本书——所以我希望没有人会抱怨(否则我将需要删除它的大部分,如果不是全部)。此外,出于同样的原因,我将避免报告代码段。不好意思。买这本书来读有关详细推理的书。

下面括号中的页码。

NOT NULL Constraint (11)非空约束(11)

最重要的列约束是 NOTNULL,它禁止 在列中使用 NULL。例行使用此约束,并删除 只有当你有充分的理由,它会帮助你避免 当您对数据进行查询时,NULL 值的复杂性。

它不是一个值 ; 它是一个标记,保存一个值可能去的位置。

还是那句“有价值但不是很有价值”的废话,剩下的对我来说似乎很合理。

(12)

简而言之,NULL 导致 SQL 中许多不规则的特性,我们将对此进行讨论 最好的办法就是记住 NULL 的情况和规则 当你无法避免的时候。

关于 SQL、 NULL 和无限:

(104)第三章: SQL 中的 NUMERIC 数据

SQL 没有接受 IEEE 模型的数学原因有几个。

...

如果 IEEE 的数学规则被允许 SQL,那么我们就需要无限的类型转换规则和一种方法来 表示转换后的无限精确数值 有足够的 NULL 的麻烦,所以让我们不要去那里。

SQL 实现尚未确定 NULL 在特定上下文中的真正含义:

3.6.2指数函数(116)

问题是,当(x < = 0) . < strong > Some SQL 时,对数没有定义 实现 返回错误消息,有些返回 无效和 DB2/ 400; 版本3版本1返回 * NEGINF (“负无穷大”的缩写) 结果。

Joe Celko 引用 David McGoveran 和 C.J. 日期:

6 NULL: SQL 中缺少数据(185)

在他们的书 Sybase 和 SQLServer 指南,大卫麦戈文 和 C.J. 日期说: “这是本作者的意见比 NULL,至少作为 目前定义和实现的 SQL,是远远超过麻烦 它们是值得的,应该避免; 它们表现得非常奇怪和 不一致的行为和可能是错误和混乱的丰富来源。 (请注意,这些意见和批评适用于任何系统 它支持 SQL 样式的 NULL,而不仅仅针对 SQLServer。)”

作为 吸毒成瘾的 NULL:

(186/187)

在本书的其余部分,我会劝你不要使用 它们 ,这可能看起来很矛盾,但实际上并非如此。想象一个 NULL 作为一种药物; 正确使用它,它对你有效,但滥用它,它可以破坏 您最好的策略是在您可以使用的时候避免使用 NULL 当你需要的时候,正确的使用它们

我在这里的独特反对意见是“正确使用它们”,这与 特定的实施行为。

6.5.1子查询谓词中的 NULLS (191/192)

人们忘记了子查询通常隐藏与 NULL 的比较。 看看这两张表:

...

结果将为空。这是 违反直觉,但是正确。

(分离器)

6.5.2标准 SQL 解决方案(193)

SQL-92解决了一些3vL (三值逻辑)问题 形式的新谓词:

< 搜索条件 > IS [ NOT ] TRUE | FALSE | UNKNOWN

但是“未知”本身就是问题的根源,所以 C.J, 在他下面引用的书中,在 4.5. 在 SQL 中避免使用 Null章中建议:

  • 不要在任何上下文中使用关键字 UNKNOWN。

阅读《未知》上的 “一边去”,下面也有链接。

6.8 NULL 和主机语言(194)

但是,您应该知道如何处理 NULL 传递给主机程序。没有标准的主机语言 定义的嵌入支持 NULL,这是另一个 避免在数据库模式中使用它们的好理由。

(分离器)

6.9无效标准的设计建议(195)

使用 NOT NULL 声明所有基表是一个好主意 只要有可能,所有列上的约束条件 谁不知道 SQL,和 NULL 是昂贵的。

反对: NULL 甚至会让熟悉 SQL 的人感到困惑, 见下文。

(195)

在 FOREIGNKEY 中应该避免使用 NULL。 SQL 允许这种“好处” 但它可能会导致信息的丢失 连接的查询。例如,在 订单表引用为 FOREIGNKEY 的库存,则 将有问题得到一个零件的清单有一个 NULL。这是 强制关系; 你不能订购不存在的零件。

(分离器)

6.9.1避免来自主机程序的 NULL (197)

您可以避免将 NULL 从主机程序放入数据库 有一定的编程纪律。

...

  1. 确定缺失数据对方案规划和报告的影响: 带有 NULL 的数字列是一个问题,因为查询 使用聚合函数可能会产生误导性的结果

(分离器)

(227)

空集的 SUM ()总是 NULL 使用此技巧时出现的编程错误是编写一个查询 可以返回不止一行。如果你不考虑它,你可能 最后一个例子是: ..。

(分离器)

10.1.1空位来源(242)

重要的是要记住 NULL 可能出现在哪里 只是列 中的一个可能值, 外部连接、带有 NULL 的算术表达式和 OLAP 运算符 这些结构通常以列的形式显示在 观点。

(分离器)

(301)

当您尝试转换时,会发现 NULL 的另一个问题 从 IN 谓词到 EXISTS 谓词。

(分离器)

16.3 ALL 谓词和极值函数(313)

起初,这两个谓词在 SQL 中是不一样的,这是违反直觉的:

...

但你必须记住极值函数的规则 在返回大值或小值之前删除所有 NULL ALL 谓词不删除 NULL,因此可以在结果中获得它们。

(分离器)

(315)

但是,标准中的定义是在 否定的,因此 NULL 得到了怀疑的好处。 ...

正如您所看到的,在 UNIQUE 中避免使用 NULL 是一个好主意 约束。

返回文章页面讨论小组译者:

NULL 被视为彼此相等 组成他们自己的小组。每个小组然后减少到一个单一的 新结果表中替换旧结果表的。

这意味着对于 GROUPBY 子句 NULL = NULL 不会 计算结果为 NULL,如3VL,但计算结果为 TRUE。

SQL 标准令人困惑:

ORDERBY 和 NULLs (329)

是否将 NULL 的排序键值视为大于或小于 非 NULL 值是实现定义的,但是..。

... 有一些 SQL 产品可以做到这一点。

1999年3月,Chris Farrar 提出了一个问题 开发人员使他检查了 SQL 标准的 < strong > 部分 我想我明白了。克里斯发现了两者之间的一些区别 说明书的一般理解和实际措辞

以此类推,我觉得 Celko 已经说得够多了。

SQLNULLs 的日期

Date 更偏向于 NULL: 在 SQL 中避免使用 NULL,句号。 事实上,他的《 SQL 和关系理论: 如何准确写作》第四章 SQL Code 标题为“ NO DUPLICATES,NO NULLS”,带有子章节 “4.4 Null 有什么问题?” 和“4.5在 SQL 中避免使用 Null”(点击链接: 感谢谷歌图书,你可以在线阅读一些网页)。

关于 SQL NULLs 的 Fabian Pascal

数据库管理中的实际问题及其借鉴 致思考者 (网上没有节选,抱歉) :

10.3实际意义

10.3.1 SQL NULLs

... SQL 受到3VL 固有问题的困扰,也受到许多问题的困扰 怪癖、复杂性、反直觉和彻头彻尾的错误[10,11] ; 其中包括:

  • 聚合函数(例如 SUM ()、 AVG ())忽略 NULL (除了 COUNT ())。
  • 没有行的表上的标量表达式计算结果错误地为 NULL,而不是0。
  • 表达式“ NULL = NULL”的计算结果为 NULL,但在 SQL 中实际上是无效的; 然而 ORDER BY 将 NULL 视为相等的(不管它们在“正则”值之前或之后是什么,都留给 DBMS 供应商)。
  • 表达式“ x IS NOT NULL”不等于“ NOT (x IS NULL)”,2VL 中的情况就是这样。

...

所有商业实现的 SQL 方言都遵循这种3VL 方法,因此, 它们不仅存在这些问题,而且还有具体的实现 问题,这些问题因产品而异

至少可以说,NULL 的概念值得怀疑。Codd 在上下文中介绍了关系模型和 NULL 的概念(并提出了不止一种 NULL!)然而,自从 Codd 最初的著作以来,关系理论已经发生了演变: 他的一些建议后来被放弃了(例如主键) ,而另一些从未流行起来(例如 θ 运算符)。在现代关系理论(真正的关系理论,我应该强调)中,NULL 根本不存在。参见第三个宣言。http://www.thethirdmanifesto.com/

SQL 语言存在向后兼容性问题。NULL 找到了进入 SQL 的方式,我们被它困住了。可以说,在 SQL 中实现 NULL是有缺陷的(SQLServer 的实现由于其 ANSI_NULLS选项使事情变得更加复杂)。

我建议避免在基表中使用 NULLable 列。


尽管也许我不应该受到诱惑,但我只是想对 NULL在 SQL 中的工作方式进行一次自己的更正:

NULL = NULL计算为 UNKNOWN

UNKNOWN是一个逻辑值。

NULL是一个数据值。

这很容易证明。

SELECT NULL = NULL

正确地在 SQLServer 中生成错误。如果结果是一个数据值,那么我们希望看到 NULL,正如这里的一些答案(错误地)所暗示的那样。

逻辑值 UNKNOWN在 SQLDML 和 SQLDDL 中的处理方式不同。

在 SQLDML 中,UNKNOWN会导致从结果集中删除行。

例如:

CREATE TABLE MyTable
(
key_col INTEGER NOT NULL UNIQUE,
data_col INTEGER
CHECK (data_col = 55)
);


INSERT INTO MyTable (key_col, data_col)
VALUES (1, NULL);

即使 CHECK条件解析为 NULL = NULL,该行的 INSERT仍然成功。这是 SQL-92(“ ANSI”)标准中规定的:

11.6表约束定义

3)

如果表约束是一个检查 约束定义,然后设 SC 为 立即执行搜索条件 包含在检查约束中 定义,并让 T 作为表名 包括在相应的表中 约束描述符; 表 不满足约束,如果和 除非

存在(从不存在的地方选择 * (SC)

是真的。

按照逻辑再仔细读一遍。

在简单的英语,我们的新行以上被给予“无罪推定”关于是 UNKNOWN和允许通过。

在 SQL DML 中,WHERE子句的规则更容易遵循:

将搜索条件应用于 每行 T。 where 的结果 子句是这些 T 行的表 搜索的结果 条件为真。

在简单的英语中,计算结果为 UNKNOWN的行将从结果集中移除。

因为 NULL表示“未知值”,两个未知值不能相等。

所以,如果按照我们的逻辑 NULL N ° 1等于 NULL N ° 2,那么我们必须告诉它:

SELECT 1
WHERE ISNULL(nullParam1, -1) = ISNULL(nullParam2, -1)

其中已知值 -1 N ° 1等于 -1 N ° 2

弗兰克多大了? 我不知道。

雪莉多大了? 我不知道。

弗兰克和雪莉是同龄人吗?

正确答案应该是“我不知道”(无效) ,而不是“没有”,因为弗兰克和雪莉 也许吧是同龄人,我们根本不知道。

科技中,对于空值是如何工作的有一个很好的解释。

Null 的意思是未知。

因此布尔表达式

Value = null

计算结果不为 false,则计算结果为 null,但如果这是 where 子句的最终结果,则不返回任何结果。这是一种实用的方法,因为返回 null 将很难想象。

有趣的是,非常重要了解以下情况:

如果在一个查询中我们有

where (value=@param Or @param is null) And id=@anotherParam

还有

  • 值 = 1
  • @ param 是空的
  • Id = 123
  • @ another Param = 123

那么

“ value =@param”计算结果为 null
“@param is null”的值为 true
“ id =@another Param”计算结果为 true

所以要求值的表达式变成

而且是真的

我们可能会想,在这里“ null 或 true”将被计算为 null,因此整个表达式将变为 null,并且行将不会被返回。

不是这样的,为什么?

因为“ null Or true”的计算结果是 true,这是非常符合逻辑的,因为如果一个操作数在 Or 操作符中为 true,那么无论另一个操作数的值是什么,操作都将返回 true。因此,另一个操作数是未知的(null)并不重要。

所以我们最终得到 true = true,因此行将被返回。

注意: 使用与“ null Or true”计算结果为 true 相同的清晰逻辑,“ null And true”计算结果为 null。

更新:
好的,为了让它更完整,我想在这里添加其余的部分,结果相对于上面的内容来说非常有趣。

“ null Or false”的值为 null,“ null And false”的值为 false. :)

当然,这种逻辑还是和以前一样不言自明。

这种混淆源于使用 NULL 产生的间接(抽象)级别。

回到“圣诞树下有什么”的类比,“未知”描述了关于盒子 A 中有什么的知识状态。

所以如果你不知道 A 盒里是什么你就说是“未知”但是 这并不意味着“未知”就在盒子里。盒子里有未知的东西,可能是某种物体,也可能什么都没有。

类似地,如果你不知道 B 盒子里有什么,你可以把你对内容的知识状态标记为“未知”。

关键在于: 你的 关于盒子 A 的知识状态等于你关于盒子 B 的知识状态。(在这两种情况下,你的知识状态都是“未知”或“我不知道盒子里有什么”。)但是盒子里的东西可能相等,也可能不相等。

回到 SQL,理想情况下,只有当您知道它们是什么时,才能够比较值。不幸的是,描述知识缺乏的标签存储在单元格本身中,所以我们倾向于使用它作为一个值。但是我们不应该使用它作为一个值,因为它会导致“当我们不知道盒子 A 中有什么和/或者我们不知道盒子 B 中有什么时,盒子 A 的内容等于盒子 B 的内容。 (逻辑上,“如果我不知道 A 盒子里有什么,如果我不知道 B 盒子里有什么,那么 A 盒子里有什么 = B 盒子里有什么”的含义是错误的。)

耶,死马。

这只是其他精彩答案的补充:

AND: The result of true and unknown is unknown, false and unknown is false,
while unknown and unknown is unknown.


OR: The result of true or unknown is true, false or unknown is unknown, while unknown or unknown is unknown.


NOT: The result of not unknown is unknown

这里的答案似乎都来自 CS 的角度,所以我想从开发人员的角度添加一个。

对于开发人员来说,NULL 非常有用。这里的答案是 NULL 意味着未知,也许在 CS 理论中是对的,不记得了,已经有一段时间了。但是在实际的开发中,至少在我的经验中,这种情况发生的概率是1% 。另外的99% 则用于值未知但已知缺失的情况。

例如:

  • 对于一个新客户来说,这并不是不可知的,大家都知道他还没有购买。

  • 当使用 ORM 时,每个 同学们 等级制度映射一个 桌子,某些值只是没有映射到某些类。

  • 当映射 树木结构时,根通常有 Parent = NULL

  • 还有更多。

我相信大多数开发人员都曾经写过 WHERE value = NULL, 没有得到任何结果,这就是他们学习 IS NULL语法的方法。看看这个问题和相关问题有多少票。

SQL 数据库是一种工具,它们应该被设计成用户最容易理解的方式。

如果您正在寻找对于两个 NULL 返回 true 的表达式,您可以使用:

SELECT 1
WHERE EXISTS (
SELECT NULL
INTERSECT
SELECT NULL
)

如果您希望将数据从一个表复制到另一个表,这将非常有帮助。

你为政府工作,登记公民信息。这包括该国每个人的国民身份证。大约40年前,一个孩子被遗弃在教堂门口,没有人知道他们的父母是谁。这个人的父亲身份是 NULL。有两个这样的人。计算与至少一个其他人(兄弟姐妹)共享同一个父亲 ID 的人数。那两个也算吗?

答案是不,你不知道,因为我们不知道他们是不是兄弟姐妹。

假设您没有 NULL选项,而是使用一些预先确定的值来表示“未知”,可能是一个空字符串或数字0或 * 字符,等等。然后在查询中可以看到 * = * 、0 = 0和“”= “”等等。这不是你想要的(根据上面的例子) ,而且你可能经常忘记这些情况(上面的例子是一个明确的边缘情况以外的普通日常思维) ,然后你需要的语言为你记住,NULL = NULL是不正确的。

需要是发明之母。

相等性测试,例如,在 case 语句 when 子句中,可以从

XYZ = NULL

XYZ IS NULL

如果我想把空格和空字符串看作等于 NULL,我通常还会使用一个相等测试,比如:

(NULLIF(ltrim( XYZ ),'') IS NULL)

再次引用圣诞节的类比:

在 SQL 中,NULL 基本上意味着 “封闭的盒子”(未知)。因此,比较两个封闭框的结果也将是未知的(空)。

我理解,对于开发人员来说,这是违反直觉的,因为在编程语言中,通常 NULL 意味着 “空盒子”(已知)。比较两个空盒子自然会得到 true/等于。

这就是例如 JavaScript 区分 nullundefined的原因。

在 WHERE 子句中有两种合理的方法来处理 NULL = NULL 比较,它们可以归结为“您说的 NULL 是什么意思?”一种方法假设 NULL 表示“未知”,另一种假设 NULL 表示“数据不存在”SQL 选择了第三种方式,这种方式到处都是错误的。

“ NULL 表示未知”解决方案: < em > 抛出错误。

未知 = 未知应计算为3VL 空。但 WHERE 子句的输出是2VL: 要么返回行,要么不返回。这就像被要求除以零并返回一个数字: 没有正确的答案。因此,您抛出一个错误,并强制程序员显式地处理这种情况。

“ NULL 意味着没有数据”解决方案: < em > 返回行。

没有数据 = 没有数据应该被评估为真。如果我比较两个人,他们有相同的名字,相同的姓氏,都没有中间名,那么说“这些人有相同的名字”是正确的

SQL 解决方案: < em > 不返回行。

这是 总是错的。如果 NULL 表示“未知”,那么您不知道是否应该返回该行,因此不应该尝试猜测。如果 NULL 表示“无数据”,则应该返回该行。无论采用哪种方式,以静默方式删除行都是不正确的,会导致问题。这是两个世界中最糟糕的。

抛开理论和实践,我支持 AlexDev: 我几乎从未遇到过“返回行”不是理想结果的情况。然而,“几乎从不”并不是“从不”,SQL 数据库通常作为大型重要系统的骨干,因此我可以看到严格并抛出错误的合理情况。

我看不到的是一个默默强迫3VL 空变成2VL 假的情况。像大多数无声类型的胁迫一样,它是一只狂暴的黄鼠狼,等待在你的系统中被释放,当黄鼠狼最终跳出来咬人时,你会有一个快乐的魔鬼时间跟踪它回到它的巢穴。

Null 不等于任何东西,包括它自己 测试对象是否为 null 的最佳方法是检查对象是否等于自身,因为 null 是唯一不等于自身的对象

Const obj = null

Log (obj = = obj)//false,则为 null

看看这篇文章