为什么 NULL = NULL 在 SQL Server 中计算结果为 false
在 SQL Server 中,如果 where 子句中有 nullParam=NULL
,则其计算结果始终为 false。这是违反直觉的,给我带来了很多错误。我确实知道 IS NULL
和 IS NOT NULL
关键字是正确的方法。但为什么 SQL Server 会这样呢?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(21)
在这种情况下,将 null 视为“未知”(或“不存在”)。在这两种情况下,您都不能说它们相等,因为您不知道它们的值。因此,null=null 的计算结果为 false(false 或 null,具体取决于您的系统),因为您不知道表示它们相等的值。此行为在 ANSI SQL-92 标准中定义。
编辑:
这取决于您的 ansi_nulls 设置。如果你关闭了 ANSI_NULLS,这将评估为 true。运行以下代码作为示例...
Think of the null as "unknown" in that case (or "does not exist"). In either of those cases, you can't say that they are equal, because you don't know the value of either of them. So, null=null evaluates to not true (false or null, depending on your system), because you don't know the values to say that they ARE equal. This behavior is defined in the ANSI SQL-92 standard.
EDIT:
This depends on your ansi_nulls setting. if you have ANSI_NULLS off, this WILL evaluate to true. Run the following code for an example...
弗兰克几岁了?我不知道(空)。
雪莉几岁了?我不知道(空)。
弗兰克和雪莉同龄吗?
正确答案应该是“我不知道”(空),而不是“不”,因为弗兰克和雪莉可能年龄相同,我们根本不知道。
How old is Frank? I don't know (null).
How old is Shirley? I don't know (null).
Are Frank and Shirley the same age?
Correct answer should be "I don't know" (null), not "no", as Frank and Shirley might be the same age, we simply don't know.
在这里我希望澄清我的立场。
NULL = NULL
计算结果为FALSE
是错误的。黑客和先生正确回答了NULL
。这就是原因。 Dewayne Christensen 在对
它们可以不同,也可以相同,你不知道,直到有人打开两件礼物。谁知道?您邀请了两个互不相识的人,但他们都给了您同样的礼物 - 罕见,但并非不可能§。
那么问题来了:这两个 UNKNOWN 呈现是否相同(相等,=)?正确答案是:未知(即
NULL
)。此示例旨在演示“..(
false
或null
,具体取决于您的系统)..”是正确答案 - 它不是,只有NULL
在3VL中是正确的(或者你可以接受给出错误答案的系统吗?)这个问题的正确答案
所以我重申:SQL 没有任何好处强迫人们解释相等性的自反属性,它指出:
.. 在 3VL 中(
TRUE
、FALSE
、NULL
)。人们的期望会符合2VL(TRUE
,FALSE
,即使在SQL中也对所有其他值有效),即x = x
对于任何可能的 x 值,始终评估为TRUE
- 无例外。另请注意,NULL 是有效的“非值”(正如其辩护者所假装的那样),可以将其指定为属性值(??)作为关系变量的一部分。因此,它们是每种类型(域)可接受的值,而不仅仅是逻辑表达式类型的值。
这就是我的观点:
NULL
作为值,是一个“奇怪的野兽”。不委婉地说,我更愿意说:废话。我认为这个表述更清晰,也更没有争议——对不起,我的英语水平很差。
这只是 NULL 的问题之一。如果可能的话,最好完全避免它们。
§我们在这里关心价值,因此两个礼物始终是两个不同的物理对象这一事实并不是一个有效的反对意见;如果您不相信,我很抱歉,这不是解释值和“对象”语义之间差异的地方(关系代数从一开始就有值语义 - 请参阅 Codd 的信息原理;我认为一些 SQL DBMS 实现者不这样做甚至不关心常见的语义)。
§§据我所知,这是自古以来就被接受的公理(以某种形式,但总是以 2VL 进行解释),并且完全因为它是如此直观。 3VL(现实中的逻辑家族)是最近的发展(但我不确定第一次开发的时间)。
旁注:如果有人介绍Bottom,单位 和 Option 类型试图证明 SQL NULL 的合理性,只有经过相当详细的检查后我才会确信,该检查将显示带有 NULL 的 SQL 实现如何拥有健全的类型系统,并最终澄清什么是 NULL(这些“值”) -不完全价值观”)确实如此。
下面我将引用一些作者的观点。 任何错误或遗漏
可能是我的,而不是原作者的。
Joe Celko on SQL NULLs
我看到 Joe Celko 经常在这个论坛上被引用。显然他是这里一位备受尊敬的作家。所以,我对自己说:“他写了哪些关于 SQL NULL 的内容?他如何解释 NULL 的众多问题?”。我的一位朋友有一本Joe Celko 的《聪明人 SQL:高级 SQL 编程,第三版》 的电子书。让我们来看看。
首先,目录。最让我印象深刻的是 NULL 在各种不同的上下文中被提及的次数:
等等。这对我来说是“令人讨厌的特殊情况”。
出于版权原因,我将摘录本书中的一些案例来探讨其中的一些案例,试图将自己限制在本质上。我认为这些引用属于“合理使用”原则,它们甚至可以刺激购买这本书 - 所以我希望没有人会抱怨(否则我将需要删除其中的大部分,如果不是全部)。此外,出于同样的原因,我将避免报告代码片段。对此感到抱歉。购买这本书来阅读有关数据推理的内容。
页码位于后面括号内。
这又是“有价值但不完全有价值”的废话。其余的对我来说似乎很明智。
关于 SQL、NULL 和无限:
SQL 实现尚未确定 NULL 在特定上下文中的真正含义:
Joe Celko 引用 David McGoveran 和 CJ Date 的话:
NULL 作为一种毒瘾:
我在这里独特的反对意见是“正确地使用它们”,这会与
具体实施行为。
(分隔符)
但未知本身就是问题的根源,因此 CJ Date,
在下面引用的他的书中,4.5 章中提出了建议。避免 SQL 中出现空值:
阅读"ASIDE" 未知,也链接如下。
(分隔符)
反对意见:即使是熟悉 SQL 的人也会对 NULL 感到困惑,
见下文。
(分隔符)
(分隔符)
(分隔符)
(分隔符)
(分隔符)
(分隔符)
讨论 GROUP BY:
这意味着对于 GROUP BY 子句 NULL = NULL 不
计算结果为 NULL,如 3VL,但计算结果为 TRUE。
SQL标准令人困惑:
等等。我认为 Celko 已经足够了。
关于 SQL NULL 的 CJ Date
CJ Date 对于 NULL 的态度更为激进:避免在 SQL 中使用 NULL。
事实上,他的SQL and Relational Theory: How to Write Accurate 第 4 章
SQL 代码的标题为“NO DUPLICATES, NO NULLS”,包含子章节
"4.4 什么是Null 错误吗?” 和“4.5 在 SQL 中避免 Null”(点击链接:
感谢 Google 图书,您可以在线阅读某些页面)。
Fabian Pascal 论 SQL NULL
来自数据库管理中的实际问题 - 参考
致思考实践者(抱歉,网上没有摘录):
Here I will hopefully clarify my position.
That
NULL = NULL
evaluate toFALSE
is wrong. Hacker and Mister correctly answeredNULL
.Here is why. Dewayne Christensen wrote to me, in a comment to Scott Ivey:
They can be different or they can be equal, you don't know until one open both presents. Who knows? You invited two people that don't know each other and both have done to you the same gift - rare, but not impossible §.
So the question: are these two UNKNOWN presents the same (equal, =)? The correct answer is: UNKNOWN (i.e.
NULL
).This example was intended to demonstrate that "..(
false
ornull
, depending on your system).." is a correct answer - it is not, onlyNULL
is correct in 3VL (or is ok for you to accept a system which gives wrong answers?)A correct answer to this question must emphasize this two points:
So I reiterate: SQL does not any good forcing one to interpret the reflexive property of equality, which state that:
.. in a 3VL (
TRUE
,FALSE
,NULL
). The expectation of people would conform to 2VL (TRUE
,FALSE
, which even in SQL is valid for all other values), i.e.x = x
always evaluate toTRUE
, for any possible value of x - no exceptions.Note also that NULLs are valid " non-values " (as their apologists pretend them to be) which one can assign as attribute values(??) as part of relation variables. So they are acceptable values of every type (domain), not only of the type of logical expressions.
And this was my point:
NULL
, as value, is a "strange beast". Without euphemism, I prefer to say: nonsense.I think that this formulation is much more clear and less debatable - sorry for my poor English proficiency.
This is only one of the problems of NULLs. Better to avoid them entirely, when possible.
§ we are concerned about values here, so the fact that the two presents are always two different physical objects are not a valid objection; if you are not convinced I'm sorry, it is not this the place to explain the difference between value and "object" semantics (Relational Algebra has value semantics from the start - see Codd's information principle; I think that some SQL DBMS implementors don't even care about a common semantics).
§§ to my knowledge, this is an axiom accepted (in a form or another, but always interpreted in a 2VL) since antiquity and that exactly because is so intuitive. 3VLs (is a family of logics in reality) is a much more recent development (but I'm not sure when was first developed).
Side note: if someone will introduce Bottom, Unit and Option Types as attempts to justify SQL NULLs, I will be convinced only after a quite detailed examination that will shows of how SQL implementations with NULLs have a sound type system and will clarify, finally, what NULLs (these "values-not-quite-values") really are.
In what follow I will quote some authors. Any error or omission is
probably mine and not of the original authors.
Joe Celko on SQL NULLs
I see Joe Celko often cited on this forum. Apparently he is a much respected author here. So, I said to myself: "what does he wrote about SQL NULLs? How does he explain NULLs numerous problems?". One of my friend has an ebook version of Joe Celko's SQL for smarties: advanced SQL programming, 3rd edition. Let's see.
First, the table of contents. The thing that strikes me most is the number of times that NULL is mentioned and in the most varied contexts:
and so on. It rings "nasty special case" to me.
I will go into some of these cases with excerpts from this book, trying to limit myself to the essential, for copyright reasons. I think these quotes fall within "fair use" doctrine and they can even stimulate to buy the book - so I hope that no one will complain (otherwise I will need to delete most of it, if not all). Furthermore, I shall refrain from reporting code snippets for the same reason. Sorry about that. Buy the book to read about datailed reasoning.
Page numbers between parenthesis in what follow.
Again this "value but not quite a value" nonsense. The rest seems quite sensible to me.
Apropos of SQL, NULLs and infinite:
SQL implementations undecided on what NULL really means in particular contexts:
Joe Celko quoting David McGoveran and C. J. Date:
NULLs as a drug addiction:
My unique objection here is to "use them properly", which interacts badly with
specific implementation behaviors.
(separator)
But UNKNOWN is a source of problems in itself, so that C. J. Date,
in his book cited below, reccomends in chapter 4.5. Avoiding Nulls in SQL:
Read "ASIDE" on UNKNOWN, also linked below.
(separator)
Objection: NULLs confuses even people that know SQL well,
see below.
(separator)
(separator)
(separator)
(separator)
(separator)
(separator)
Discussing GROUP BY:
This means that for GROUP BY clause NULL = NULL does not
evaluate to NULL, as in 3VL, but it evaluate to TRUE.
SQL standard is confusing:
And so on. I think is enough by Celko.
C. J. Date on SQL NULLs
C. J. Date is more radical about NULLs: avoid NULLs in SQL, period.
In fact, chapter 4 of his SQL and Relational Theory: How to Write Accurate
SQL Code is titled "NO DUPLICATES, NO NULLS", with subchapters
"4.4 What's Wrong with Nulls?" and "4.5 Avoiding Nulls in SQL" (follow the link:
thanks to Google Books, you can read some pages on-line).
Fabian Pascal on SQL NULLs
From its Practical Issues in Database Management - A Reference
for the Thinking Practitioner (no excerpts on-line, sorry):
这里的答案似乎都来自于CS的角度,所以我想从开发者的角度添加一个。
对于开发人员来说 NULL 非常有用。这里的答案说NULL意味着未知,也许在CS理论中这是真的,不记得了,已经有一段时间了。但在实际开发中,至少根据我的经验,这种情况发生的概率约为 1%。另外 99% 用于该值并非未知但已知不存在的情况。
例如:
使用软删除时,
deletedAt = NULL
并不意味着我们不知道它何时被删除,而是意味着它没有被删除。Client.LastPurchase
,对于新客户。这不是未知的,已知他还没有购买。当使用带有表的ORM时,每个类 层次结构映射,有些值只是没有映射到某些类。
映射树结构时,根通常会有
Parent = NULL
还有更多...
我确信大多数开发人员在某个时候都会写过
WHERE value = NULL
,没有得到任何结果,这就是他们了解
IS NULL
语法的方式。只要看看这个问题和相关问题有多少票即可。SQL 数据库是一种工具,应该以最容易让用户理解的方式进行设计。
The answers here all seem to come from a CS perspective so I want to add one from a developer perspective.
For a developer NULL is very useful. The answers here say NULL means unknown, and maybe in CS theory that's true, don't remember, it's been a while. In actual development though, at least in my experience, that happens about 1% of the time. The other 99% it is used for cases where the value is not UNKNOWN but it is KNOWN TO BE ABSENT.
For example:
When using soft deletes,
deletedAt = NULL
doesn't mean we don't know when it was deleted, it means it wasn't deleted.Client.LastPurchase
, for a new client. It is not unknown, it is known that he hasn't made a purchase yet.When using an ORM with a Table per Class Hierarchy mapping, some values are just not mapped for certain classes.
When mapping a tree structure a root will usually have
Parent = NULL
And many more...
I'm sure most developers at some point wrote
WHERE value = NULL
,didn't get any results, and that's how they learned about
IS NULL
syntax. Just look how many votes this question and the linked ones have.SQL Databases are a tool, and they should be designed the way which is easiest for their users to understand.
仅仅因为您不知道两件事是什么,并不意味着它们是相等的。如果当您想到
NULL
时,您会想到“NULL”(字符串),那么您可能需要不同的相等性测试,例如 Postgresql 的IS DISTINCT FROM
ANDIS NOT DISTINCT FROM
来自 PostgreSQL 文档“比较函数和运算符”
Just because you don't know what two things are, does not mean they're equal. If when you think of
NULL
you think of “NULL” (string) then you probably want a different test of equality like Postgresql'sIS DISTINCT FROM
ANDIS NOT DISTINCT FROM
From the PostgreSQL docs on "Comparison Functions and Operators"
也许这取决于情况,但我认为
NULL=NULL
的计算结果为NULL
就像大多数以 NULL 作为操作数的操作一样。Maybe it depends, but I thought
NULL=NULL
evaluates toNULL
like most operations with NULL as an operand.在 technet 有一个很好的解释了解空值的工作原理。
空意味着未知。
因此,布尔表达式
value=null 的
计算结果不是 false,而是 null,但如果这是 where 子句的最终结果,则不会返回任何内容。这是一种实用的方法,因为返回 null 很难想象。
理解以下内容很有趣并且非常重要:
如果在查询中我们有
value
那么
“value=@param”的计算结果为 null< br>
“@param is null”的计算结果为 true
"id=@anotherParam" 计算结果为 true
所以要计算的表达式变为
(null Or true) And true
我们可能会想,这里“null Or true”将计算为 null,因此整个表达式变为 null,并且行将不会被返回。
事实并非如此。为什么?
因为“null Or true”的计算结果为 true,这是非常合乎逻辑的,因为如果 Or 运算符的一个操作数为 true,则无论另一个操作数的值如何,该操作都将返回 true。因此,另一个操作数未知(空)并不重要。
所以我们最终得到 true=true 并且该行将被返回。
注意:使用与“null Or true”计算结果为 true 相同的清晰逻辑,“null And true”计算结果为 null。
更新:
好吧,为了使它完整,我也想在这里添加其余的内容,这与上面的内容相比非常有趣。
“null Or false”计算结果为 null,“null And false”计算结果为 false。 :)
逻辑当然还是像以前一样不言而喻。
At technet there is a good explanation for how null values work.
Null means unknown.
Therefore the Boolean expression
value=null
does not evaluate to false, it evaluates to null, but if that is the final result of a where clause, then nothing is returned. That is a practical way to do it, since returning null would be difficult to conceive.
It is interesting and very important to understand the following:
If in a query we have
and
then
"value=@param" evaluates to null
"@param is null" evaluates to true
"id=@anotherParam" evaluates to true
So the expression to be evaluated becomes
(null Or true) And true
We might be tempted to think that here "null Or true" will be evaluated to null and thus the whole expression becomes null and the row will not be returned.
This is not so. Why?
Because "null Or true" evaluates to true, which is very logical, since if one operand is true with the Or-operator, then no matter the value of the other operand, the operation will return true. Thus it does not matter that the other operand is unknown (null).
So we finally have true=true and thus the row will be returned.
Note: with the same crystal clear logic that "null Or true" evaluates to true, "null And true" evaluates to null.
Update:
Ok, just to make it complete I want to add the rest here too which turns out quite fun in relation to the above.
"null Or false" evaluates to null, "null And false" evaluates to false. :)
The logic is of course still as self-evident as before.
MSDN 有一篇关于空值和它们产生的三种状态逻辑。
简而言之,SQL92 规范将 NULL 定义为未知,并且在以下运算符中使用 NULL 会导致外行人意外的结果:
MSDN has a nice descriptive article on nulls and the three state logic that they engender.
In short, the SQL92 spec defines NULL as unknown, and NULL used in the following operators causes unexpected results for the uninitiated:
至少可以说,NULL 的概念是有问题的。 Codd 在上下文中引入了关系模型和 NULL 的概念(并继续提出了不止一种 NULL!)但是,自 Codd 的原始著作以来,关系理论已经发展:他的一些建议已被删除(例如主键)还有一些从未流行起来(例如 theta 运算符)。在现代关系理论(真正的关系理论,我应该强调)中,NULL 根本不存在。参见第三宣言。 http://www.thethirdmanifesto.com/
SQL 语言存在向后兼容性问题。 NULL 进入了 SQL,而我们却被它困住了。可以说,SQL 中
NULL
的实现是有缺陷的(SQL Server 的实现由于它的ANSI_NULLS
选项而使事情变得更加复杂)。我建议避免在基表中使用可空列。
尽管也许我不应该受到诱惑,但我只是想对
NULL
在 SQL 中的工作方式进行自己的更正:NULL
=NULL
计算结果为UNKNOWN
。UNKNOWN
是一个逻辑值。NULL
是一个数据值。这很容易证明,例如
SELECT NULL = NULL
在 SQL Server 中正确生成错误。如果结果是一个数据值,那么我们会期望看到
NULL
,正如这里的一些答案(错误地)建议的那样。SQL DML 和 SQL DDL 中对逻辑值
UNKNOWN
的处理方式分别不同。在 SQL DML 中,
UNKNOWN
会导致从结果集中删除行。例如:
即使
CHECK
条件解析为NULL = NULL
,该行的INSERT
也会成功。这是在 SQL-92(“ANSI”)标准中定义的:按照逻辑再仔细阅读一遍。
用简单的英语来说,我们上面的新行被赋予了“未知的好处”,即“未知”并被允许通过。
在 SQL DML 中,
WHERE
子句的规则更容易遵循:简而言之,计算结果为
UNKNOWN
的行将从结果集中删除。The concept of NULL is questionable, to say the least. Codd introduced the relational model and the concept of NULL in context (and went on to propose more than one kind of NULL!) However, relational theory has evolved since Codd's original writings: some of his proposals have since been dropped (e.g. primary key) and others never caught on (e.g. theta operators). In modern relational theory (truly relational theory, I should stress) NULL simply does not exist. See The Third Manifesto. http://www.thethirdmanifesto.com/
The SQL language suffers the problem of backwards compatibility. NULL found its way into SQL and we are stuck with it. Arguably, the implementation of
NULL
in SQL is flawed (SQL Server's implementation makes things even more complicated due to itsANSI_NULLS
option).I recommend avoiding the use of NULLable columns in base tables.
Although perhaps I shouldn't be tempted, I just wanted to assert a corrections of my own about how
NULL
works in SQL:NULL
=NULL
evaluates toUNKNOWN
.UNKNOWN
is a logical value.NULL
is a data value.This is easy to prove e.g.
SELECT NULL = NULL
correctly generates an error in SQL Server. If the result was a data value then we would expect to see
NULL
, as some answers here (wrongly) suggest we would.The logical value
UNKNOWN
is treated differently in SQL DML and SQL DDL respectively.In SQL DML,
UNKNOWN
causes rows to be removed from the resultset.For example:
The
INSERT
succeeds for this row, even though theCHECK
condition resolves toNULL = NULL
. This is due defined in the SQL-92 ("ANSI") Standard:Read that again carefully, following the logic.
In plain English, our new row above is given the 'benefit of the doubt' about being
UNKNOWN
and allowed to pass.In SQL DML, the rule for the
WHERE
clause is much easier to follow:In plain English, rows that evaluate to
UNKNOWN
are removed from the resultset.因为
NULL
表示“未知值”,并且两个未知值不能相等。因此,如果按照我们的逻辑
NULL
N°1 等于NULL
N°2,那么我们必须以某种方式告诉我们:已知值
-1 N°1 等于
-1
N°2Because
NULL
means 'unknown value' and two unknown values cannot be equal.So, if to our logic
NULL
N°1 is equal toNULL
N°2, then we have to tell that somehow:where known value
-1
N°1 is equal to-1
N°2有两种明智的方法可以处理 WHERE 子句中的 NULL = NULL 比较,它们归结为“NULL 是什么意思?”一种方式假设 NULL 表示“未知”,另一种方式假设 NULL 表示“数据不存在”。 SQL 选择了第三种方式,但这是完全错误的。
“NULL 表示未知”解决方案: 抛出错误。
Unknown = 未知应计算为 3VL null。但 WHERE 子句的输出是 2VL:您要么返回该行,要么不返回。这就像被要求除以零并返回一个数字:没有正确的响应。因此,您会抛出一个错误,并强制程序员显式处理这种情况。
“NULL 表示没有数据”解决方案: 返回行。
无数据 = 没有数据应评估为 true。如果我比较两个人,他们有相同的名字和相同的姓氏,并且都没有中间名,那么说“这些人有相同的名字”是正确的。
SQL 解决方案: 不要返回行。
这总是错误的。如果 NULL 表示“未知”,那么您不知道是否应该返回该行,并且您不应该尝试猜测。如果 NULL 表示“没有数据”,那么您应该返回该行。无论哪种方式,默默地删除该行都是不正确的,并且会导致问题。这是两全其美的最糟糕的情况。
抛开理论,从实际角度来说,我同意 AlexDev 的观点:我几乎从未遇到过“返回行”不是所需结果的情况。然而,“几乎从不”并不是“从不”,而且 SQL 数据库通常充当大型重要系统的支柱,因此我可以看到严格并抛出错误的公平案例。
我看不到的是默默地将 3VL null 强制为 2VL false 的情况。像大多数无声类型的强制一样,它就像一只疯狂的黄鼠狼等待着在你的系统中被释放,当黄鼠狼最终跳出来咬某人时,你就会有一个快乐的恶魔追踪它回到它的巢穴。
There are two sensible ways to handle NULL = NULL comparisons in a WHERE clause, and they boil down to "What do you mean by NULL?" One way assumes NULL means "unknown," and the other assumes NULL means "data does not exist." SQL has chosen a third way which is wrong all around.
The "NULL means unknown" solution: Throw an error.
Unknown = unknown should evaluate to 3VL null. But the output of a WHERE clause is 2VL: You either return the row or you don't. It's like being asked to divide by zero and return a number: There is no correct response. So you throw an error instead, and force the programmer to explicitly handle this situation.
The "NULL means no data" solution: Return the row.
No data = no data should evaluate to true. If I'm comparing two people, and they have the same first name, and the same last name, and neither has a middle name, then it is correct to say "These people have the same name."
The SQL solution: Don't return the row.
This is always wrong. If NULL means "unknown," then you don't know if the row should be returned or not, and you should not try to guess. If NULL means "no data," then you should return the row. Either way, silently removing the row is incorrect and will cause problems. It's the worst of both worlds.
Setting aside theory and speaking in practical terms, I'm with AlexDev: I have almost never encountered a case where "return the row" was not the desired result. However, "almost never" is not "never," and SQL databases often serve as the backbones of big important systems, so I can see a fair case for being rigorous and throwing an error.
What I cannot see is a case for silently coercing 3VL null into 2VL false. Like most silent type coercions, it's a rabid weasel waiting to be set loose in your system, and when the weasel finally jumps out and bites someone, you'll have the merry devil of a time tracking it back to its nest.
NULL 不等于任何东西,甚至不等于它本身。我个人理解 NULL 行为的解决方案是尽可能避免使用它:)。
NULL isn't equal to anything, not even itself. My personal solution to understanding the behavior of NULL is to avoid using it as much as possible :).
问题:
一个未知数是否等于另一个未知数?
(空=空)
这个问题是没人能回答的,所以它默认为 true 或 false,具体取决于您的 ansi_nulls 设置。
然而问题是:
这个未知变量是未知的吗?
这个问题完全不同,可以用 true 来回答。
nullVariable = null 正在比较值
nullVariable is null 正在比较变量的状态
The question:
Does one unknown equal another unknown?
(NULL = NULL)
That question is something no one can answer so it defaults to true or false depending on your ansi_nulls setting.
However the question:
Is this unknown variable unknown?
This question is quite different and can be answered with true.
nullVariable = null is comparing the values
nullVariable is null is comparing the state of the variable
混乱源自使用 NULL 所产生的间接(抽象)级别。
回到“圣诞树下有什么”的类比,“未知”描述了关于盒子 A 中的内容的知识状态。
因此,如果你不知道盒子 A 中有什么,你就说它是“未知”,但是 这并不意味着“未知”在盒子内。盒子里有一些未知的东西,可能是某种物体,或者盒子里可能什么也没有。
同样,如果您不知道方框 B 中的内容,您可以将您对内容的了解状态标记为“未知”。
因此,关键在于:您对方框 A 的了解程度等于您对方框 B 的了解程度。 (在这两种情况下,您的知识状态都是“未知”或“我不知道盒子里有什么”。)但是盒子里的内容可能相同,也可能不同。
回到 SQL,理想情况下,您应该只有在知道值是什么时才能比较它们。 不幸的是,描述缺乏知识的标签存储在单元格本身中,因此我们很想将其用作值。但我们不应该将其用作值,因为这会导致“当我们不知道盒子 A 中的内容和/或我们不知道盒子 B 中的内容时,盒子 A 的内容等于盒子 B 的内容。
(从逻辑上讲,“如果我不知道盒子 A 里有什么,如果我不知道盒子 B 里有什么,那么盒子 A 里的东西 = 盒子 B 里有什么”的含义是错误的。)
是的,死马。
The confusion arises from the level of indirection (abstraction) that comes about from using NULL.
Going back to the "what's under the Christmas tree" analogy, "Unknown" describes the state of knowledge about what is in Box A.
So if you don't know what's in Box A, you say it's "Unknown", but that doesn't mean that "Unknown" is inside the box. Something other than unknown is in the box, possibly some kind of object, or possibly nothing is in the box.
Similarly, if you don't know what's in Box B, you can label your state of knowledge about the contents as being "Unknown".
So here's the kicker: Your state of knowledge about Box A is equal to your state of knowledge about Box B. (Your state of knowledge in both cases is "Unknown" or "I don't know what's in the Box".) But the contents of the boxes may or may not be equal.
Going back to SQL, ideally you should only be able to compare values when you know what they are. Unfortunately, the label that describes a lack of knowledge is stored in the cell itself, so we're tempted to use it as a value. But we should not use that as a value, because it would lead to "the content of Box A equals the content of Box B when we don't know what's in Box A and/or we don't know what's in Box B.
(Logically, the implication "if I don't know what's in Box A and if I don't know what's in Box B, then what's in Box A = What's in Box B" is false.)
Yay, Dead Horse.
null 在 SQL 中是未知的,因此我们不能期望两个未知数相同。
但是,您可以通过将 ANSI_NULLS 设置为 Off(默认情况下为 On)来获得该行为
您将能够对空值使用 = 运算符
null is unknown in sql so we cant expect two unknowns to be same.
However you can get that behavior by setting ANSI_NULLS to Off(its On by Default)
You will be able to use = operator for nulls
您为政府工作,登记有关公民的信息。这包括该国每个人的国民身份证。大约40年前,一个孩子被留在教堂门口,没有人知道他们的父母是谁。此人的父亲 ID 为
NULL
。这样的人有两个。计算与至少一个其他人(兄弟姐妹)共享同一父亲 ID 的人数。这两个你也算吗?答案是否定的,你不知道,因为我们不知道他们是否是兄弟姐妹。
假设你没有 NULL 选项,而是使用一些预先确定的值来表示“未知”,可能是空字符串或数字 0 或 * 字符等。那么你会在您的查询中包含 * = *、0 = 0 和“” = “”等。这不是您想要的(如上面的示例所示),而且您可能经常忘记这些情况(上面的示例是一个超出日常思维的清晰边缘案例),那么您需要语言来记住
NULL = NULL
不是真的。需要是发明之母。
You work for the government registering information about citizens. This includes the national ID for every person in the country. A child was left at the door of a church some 40 years ago, nobody knows who their parents are. This person's father ID is
NULL
. Two such people exist. Count people who share the same father ID with at least one other person (people who are siblings). Do you count those two too?The answer is no, you don’t, because we don’t know if they are siblings or not.
Suppose you don’t have a
NULL
option, and instead use some pre-determined value to represent “the unknown”, perhaps an empty string or the number 0 or a * character, etc. Then you would have in your queries that * = *, 0 = 0, and “” = “”, etc. This is not what you want (as per the example above), and as you might often forget about these cases (the example above is a clear fringe case outside ordinary everyday thinking), then you need the language to remember for you thatNULL = NULL
is not true.Necessity is the mother of invention.
再次引用圣诞节的比喻:
在 SQL 中,NULL 基本上意味着“封闭的盒子”(未知)。因此,比较两个封闭框的结果也将是未知的(空)。
我知道,对于开发人员来说,这是违反直觉的,因为在编程语言中,NULL 通常意味着“空盒子”(已知)。比较两个空盒子自然会得到 true / equal。
这就是 JavaScript 区分
null
和undefined
的原因。To quote the Christmas analogy again:
In SQL, NULL basically means "closed box" (unknown). So, the result of comparing two closed boxes will also be unknown (null).
I understand, for a developer, this is counter-intuitive, because in programming languages, often NULL rather means "empty box" (known). And comparing two empty boxes will naturally yield true / equal.
This is why JavaScript for example distinguishes between
null
andundefined
.只是对其他精彩答案的补充:
Just an addition to other wonderful answers:
如果您正在寻找对两个 NULL 返回 true 的表达式,您可以使用:
如果您想要将数据从一个表复制到另一个表,这会很有帮助。
If you are looking for an expression returning true for two NULLs you can use:
It is helpful if you want to replicate data from one table to another.
例如,在 case 语句中的when子句中,相等性测试可以从 改为
。
如果我想将空格和空字符串视为等于 NULL,我也经常使用相等性测试,例如:
The equality test, for example, in a case statement when clause, can be changed from
to
If I want to treat blanks and empty string as equal to NULL I often also use an equality test like:
Null 不等于任何东西,包括它自己
测试对象是否为 null 的最佳方法是检查该对象是否等于自身,因为 null 是唯一不等于自身的对象
const obj = null
console.log(obj==obj) //false, then it's null
查看这篇文章
Null isn't equal to anything including itself
Best way to test if an object is null is to check whether the object equals itself since null is the only object not equal to itself
const obj = null
console.log(obj==obj) //false, then it's null
Check this article