为什么NULL = NULL在SQL Server中评估为false

eenim 发布于 2019-11-10 null 最后更新 2019-11-10 12:10 211 浏览

在SQL服务器中,如果在where子句中有nullParam=NULL,它总是计算为false。这是违反直觉的,并且导致我很多错误。我了解IS NULLIS NOT NULL关键字是正确的方法。但为什么SQL服务器的行为如此呢?

已邀请:

hrerum

赞同来自:

因为NULL表示“未知值”,并且两个未知值不能相等。 所以,如果我们的逻辑NULL N°1等于NULL N°2,那么我们必须以某种方式告诉我:

SELECT 1
WHERE ISNULL(nullParam1, -1) = ISNULL(nullParam2, -1)
其中已知值-1 N°1等于-1 N°2

edolor

赞同来自:

至少可以说,NULL的概念是值得怀疑的。 Codd在上下文中介绍了关系模型和NULL的概念(并继续提出多种类型的NULL!)然而,自从Codd的原始着作以来,关系理论已经发展:他的一些提议已被删除(例如主键)和其他人从未接触过(例如theta运营商)。在现代关系理论(真正的关系理论,我应该强调)中,NULL根本就不存在。参见第三份宣言。 http://www.thethirdmanifesto.com/ SQL语言存在向后兼容性问题。 NULL找到了进入SQL的方式,我们坚持使用它。可以说,SQL中NULL的实现存在缺陷(由于其ANSI_NULLS选项,SQL Server的实现使事情变得更加复杂)。 我建议避免在基表中使用NULLable列。


虽然也许我不应该受到诱惑,但我只想断言我自己对NULL在SQL中的工作方式的修正: NULL = NULL评估为UNKNOWNUNKNOWN是一个逻辑值。 NULL是一个数据值。 这很容易证明,例如 SELECT NULL = NULL 在SQL Server中正确生成错误。如果结果是一个数据值,那么我们期望看到NULL,因为这里的一些答案(错误地)表明我们会这样做。 在SQL DML和SQL DDL中,逻辑值UNKNOWN的处理方式不同。 在SQL DML中,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 = NULLINSERT也会成功执行此行。这是在SQL-92(“ANSI”)标准中定义的:
11.6 table constraint definition 3) If the table constraint is a check constraint definition, then let SC be the search condition immediately contained in the check constraint definition and let T be the table name included in the corresponding table constraint descriptor; the table constraint is not satisfied if and only if EXISTS ( SELECT * FROM T WHERE NOT ( SC ) ) is true.
按照逻辑再次仔细阅读。 用简单的英语,我们上面的新行给出了关于成为UNKNOWN并允许通过的“怀疑的好处”。 在SQL DML中,WHERE子句的规则更容易遵循:
The search condition is applied to each row of T. The result of the where clause is a table of those rows of T for which the result of the search condition is true.
在简单的英语中,从结果集中删除计算为UNKNOWN的行。

saut

赞同来自:

内容太长未翻译

det

赞同来自:

technet,可以很好地解释null值的工作原理。 Null意味着未知。 因此布尔表达式 值=空 不计算为false,它计算为null,但如果这是where子句的最终结果,则不返回任何内容。这是一种实用的方法,因为返回null将很难设想。 了解以下内容非常有趣且非常重要: 如果在查询中我们有

where (value=@param Or @param is null) And id=@anotherParam
  • value = 1
  • @param为null
  • id = 123
  • @ anotherParam = 123
然后 “value = @ param”计算为null
“@param为null”的计算结果为true
“id = @ anotherParam”的计算结果为true 所以要评估的表达式就变成了 (null或true)并且是真的 我们可能会想到这里“null或true”将被计算为null,因此整个表达式变为null并且不会返回该行。 事实并非如此。为什么? 因为“null或true”求值为true,这是非常合乎逻辑的,因为如果一个操作数对于Or运算符为真,那么无论另一个操作数的值如何,操作都将返回true。因此,其他操作数未知(null)并不重要。 所以我们最终得到true = true,因此将返回该行。 注意:使用相同的清晰逻辑“null或true”求值为true,“null和true”求值为null。 更新:点击 好吧,只是为了完成它我想在这里添加其余部分,结果与上述相关非常有趣。 “null或false”计算为null,“null和false”计算结果为false。 :) 逻辑当然仍然像以前一样不言自明。

yhic

赞同来自:

混淆源于使用NULL产生的间接(抽象)级别。 回到“圣诞树下的东西”类比,“未知”描述了关于框A中的内容的知识状态。 因此,如果您不知道方框A中的内容,您说它是“未知”,但这并不意味着框内有“未知”。盒子里面不是未知的东西,可能是某种物体,或者箱子里什么都没有。 同样,如果您不知道方框B中的内容,您可以将有关内容的知识状态标记为“未知”。 所以这里是踢球者:你对Box A的了解状态与你对Box B的知识状态相同。(你在两种情况下的知识状态都是“未知”或“我不知道盒子里有什么”。)但是方框的内容可能相同也可能不相同。 回到SQL,理想情况下,只有在知道它们是什么时才能比较值。不幸的是,描述缺乏知识的标签存储在单元格本身中,因此我们很想将其用作值。但我们不应该将其作为一个价值,因为当我们不知道方框A中的内容和/或我们不知道方框B中的内容时,它会导致“方框A的内容等于方框B的内容”。 (逻辑上,暗示“如果我不知道方框A中有什么,如果我不知道方框B中有什么,那么方框A中的内容=方框B中的内容”是错误的。) 耶,死马。

nsequi

赞同来自:

仅仅因为你不知道两件事是什么,并不代表他们是平等的。如果你想到NULL你会想到“NULL”(字符串)那么你可能想要一个不同的相等测试,比如Postgresql的IS DISTINCT FROMIS NOT DISTINCT FROM http://www.postgresql.org/docs/8.4/static/functions-comparison.html

expression IS DISTINCT FROM expression expression IS NOT DISTINCT FROM expression For non-null inputs, IS DISTINCT FROM is the same as the <> operator. However, if both inputs are null it returns false, and if only one input is null it returns true. Similarly, IS NOT DISTINCT FROM is identical to = for non-null inputs, but it returns true when both inputs are null, and false when only one input is null. Thus, these constructs effectively act as though null were a normal data value, rather than "unknown".

kqui

赞同来自:

在这种情况下,将null视为“未知”(或“不存在”)。在任何一种情况下,你都不能说它们是平等的,因为你不知道它们中的任何一个的价值。因此,null = null的计算结果为true(false或null,具体取决于您的系统),因为您不知道值是否相等。此行为在ANSI SQL-92标准中定义。 编辑: 这取决于您的ansi_nulls设置。如果你关闭了ANSI_NULLS,那么这将评估为true。运行以下代码以获取示例...

set ansi_nulls off
if null = null
    print 'true'
else
    print 'false'
set ansi_nulls ON
if null = null
    print 'true'
else
    print 'false'

set

赞同来自:

也许这取决于,但我认为NULL=NULL评估为NULL,就像大多数以NULL作为操作数的操作一样。

kquam

赞同来自:

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

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

matque

赞同来自:

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

jvitae

赞同来自:

null在sql中是未知的,所以我们不能指望两个未知数是相同的。 但是,您可以通过将ANSI_NULLS设置为Off(默认为On)来获取该行为 您将能够使用=运算符作为空值

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

ksit

赞同来自:

弗兰克多大了?我不知道(null)。 雪莉多大了?我不知道(null)。 弗兰克和雪莉的年龄相同吗? 正确的答案应该是“我不知道”(null),而不是“不”,因为Frank和Shirley可能是同一年龄,我们根本就不知道。

qquas

赞同来自:

问题:
一个未知是否等于另一个未知?
(NULL = NULL)
这个问题是没有人可以回答的问题,因此默认为true或false,具体取决于你的ansi_nulls设置。 但问题是:
这个未知变量是未知的吗?
这个问题是完全不同的,可以回答是真的。 nullVariable = null正在比较值
nullVariable为null是比较变量的状态

liste

赞同来自:

MSDN在空值上有一个很好的描述性article以及它们产生的三个状态逻辑。 简而言之,SQL92规范将NULL定义为未知,并且在以下运算符中使用的NUL会导致未初始化的意外结果:

= 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