在SQL Server中,如果 nullParam=NULL
在where子句中,则其总值为false。这是违反直觉的,并导致了我很多错误。我确实了解IS NULL
和IS NOT NULL
关键字是正确的方法。但是,为什么SQL Server会表现这种方式?
在SQL Server中,如果 nullParam=NULL
在where子句中,则其总值为false。这是违反直觉的,并导致了我很多错误。我确实了解IS NULL
和IS NOT NULL
关键字是正确的方法。但是,为什么SQL Server会表现这种方式?
Answers:
在这种情况下,请将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'
(NaN == NaN) == false && (NaN != Nan) == false && (NaN < NaN) == false && ...
-因为,如果不是数字,那么就不能多说了。这是未知的。这个概念是合理的,即使对于从未见过的人来说都是不直观的。
NULL
SQL表达式中的每个表达式都可以视为一个不同的数学变量。因此,表达式NULL = NULL
应视为x = y
,其中x
和y
是未绑定变量。现在,如果有人问您,的值是x = y
多少?唯一合理的答案是“一些z
”。因此,我们有(x = y) = z
-或将其转录回SQL的方法(NULL = NULL) = NULL
。
弗兰克几岁了?我不知道(空)。
雪莉几岁?我不知道(空)。
弗兰克和雪莉年龄相同吗?
正确答案应该是“我不知道”(空),而不是“不”,因为弗兰克和雪莉可能是同一年龄,我们根本不知道。
null = null
产量FALSE
却不是NULL
。
我希望在这里阐明我的立场。
认为NULL = NULL
对FALSE
是错误的。黑客和先生正确回答NULL
。这就是为什么。戴维·克里斯滕森(Dewayne Christensen)在给斯科特·艾维(Scott Ivey)的评论中写信给我:
由于是十二月,所以我们以一个季节性的例子为例。我在树下有两个礼物。现在,你告诉我我是否有两个相同的东西。
它们可以是不同的,也可以是相等的,直到一个打开同时出现时才知道。谁知道?您邀请了两个彼此都不认识并且都向您做过相同礼物的人-罕见,但并非不可能§。
那么问题来了:这两个UNKNOWN呈现的是否相同(等于=)?正确答案是:未知(即NULL
)。
本示例旨在说明 “ ..(false
或null
,取决于您的系统)..”是正确的答案-并非如此,只有 NULL
在3VL中才是正确的(或者您可以接受给出错误答案的系统吗? )
对这个问题的正确答案必须强调以下两点:
因此,我重申:SQL并不能很好地强迫人们解释相等的反身性质,该性质表明:
for any x, x = x
§§(用通俗的英语说:无论话语领域如何,“事物”始终等于自身)。
..在3VL( ,TRUE
,)。FALSE
NULL
人们的期望符合2VL(TRUE
,FALSE
即使在SQL中也对所有其他值都有效),即对于x的任何可能值x = x
始终取为 TRUE
,无例外。
还请注意,NULL是有效的“ 非值 ”(因为其辩护者假装为),可以将其指定为关系变量的一部分的属性值(??)。因此,它们不仅是逻辑表达式类型的所有类型(域)的可接受值。
而这是我的观点:NULL
作为价值,是一个“奇怪的野兽”。没有委婉的说法,我更愿意说:胡说八道。
我认为这种表述更加清晰和值得商--对我英语水平不佳表示抱歉。
这仅仅是一个的空值的问题。如果可能,最好完全避免使用它们。
§我们在这里关注值,因此两个礼物总是两个不同的物理对象这一事实不是有效的反对;如果您不确信我很抱歉,这里不是解释值和“对象”语义之间差异的地方(关系代数从一开始就具有值语义-请参阅Codd的信息原理;我认为某些SQL DBMS实现者没有甚至不在乎常见的语义)。
§§据我所知,这是自古代以来就接受的一种公理(以一种形式或另一种形式,但始终以2VL解释),而这正是因为如此直观。3VL(实际上是逻辑系列)是最近的开发(但我不确定何时首次开发)。
旁注:如果有人将Bottom,Unit和Option Type 引入作为证明SQL NULL合理性的尝试,那么只有在进行了相当详细的检查之后,我才会相信我,这将显示具有NULL的SQL实现如何具有健全的类型系统,并最终阐明,真正的NULL是什么(这些“值不等于值”)。
接下来,我将引用一些作者的话。任何错误或遗漏可能都是我的,而并非原始作者。
Joe Celko关于SQL NULL
我看到Joe Celko在该论坛上经常被引用。显然他是这里一位备受尊敬的作家。因此,我对自己说:“他写了什么有关SQL NULL的文章?他如何解释NULL带来的许多问题?”。我的一个朋友拥有Joe Celko的SQL的电子书版本,该版本是关于聪明人的:高级SQL编程,第三版。让我们来看看。
首先是目录。最让我印象深刻的是在最不同的情况下提到NULL的次数:
3.4算术和NULL 109
3.5往返于NULL的值110
3.5.1 NULLIF()函数110
6 NULL:SQL 185中的数据丢失
6.4比较NULL 190
6.5 NULL和逻辑190
6.5.1 NULL在子查询谓词191
6.5.2中SQL解决方案193
6.6数学和NULL 193
6.7函数和NULL 193
6.8 NULL和主机语言194
6.9 NULL的设计建议195
6.9.1从主机程序中避免NULL 197
6.10有关多个NULL值的说明198
10.1 IS NULL谓词241
10.1。 1 NULL的来源242
...
等等。它给我敲响了“讨厌的特例”。
在本书中,我将摘录其中一些案例,出于版权方面的考虑,试图将自己局限于基本内容。我认为这些报价属于“合理使用”原则,甚至可以刺激人们购买该书-因此,我希望没有人会抱怨(否则,即使不是全部,我也要删除其中的大部分内容)。此外,出于相同的原因,我将避免报告代码片段。对于那个很抱歉。购买该书以了解有关数据推理的知识。
括号之间的页码如下。
非空约束(11)
最重要的列约束是NOT NULL,它禁止在列中使用NULL。定期使用此约束,只有在有充分理由时才将其删除。对数据进行查询时,它将帮助您避免NULL值的复杂性。
这不是价值 ; 它是一个标记,用于保存可能存在值的位置。
同样,这种“有价值但不完全有价值”胡说八道。其余的对我来说似乎很明智。
(12)
简而言之,NULL会在SQL中引起很多不规则的功能,我们将在后面讨论。最好的选择是记住无法避免的情况和NULL规则。
SQL,NULL和无限的用法:
(104)第3章:SQL中的数值数据
由于多种原因,SQL尚未接受IEEE数学模型。
...
如果SQL中允许使用IEEE数学规则,那么我们将需要无限的类型转换规则以及一种在转换后表示无限精确数值的方法。人们对NULL有足够的麻烦,所以我们不要去那里。
SQL实现尚未确定NULL在特定上下文中的真正含义:
3.6.2指数函数(116)
问题是(x <= 0)时对数不确定。一些SQL实现返回一条错误消息,一些返回NULL和DB2 / 400。其版本3版本1返回* NEGINF(“负无穷大”的缩写)。
Joe Celko引用David McGoveran和CJ日期:
6 NULL:SQL中缺少数据(185)
David McGoveran和CJ Date 在他们的《 Sybase和SQL Server指南》一书中说:“作者认为,比NULL(至少目前在SQL中已定义和实现)比NULL麻烦得多,应避免,应避免。它们显示出非常奇怪和不一致的行为,并且可能是错误和混乱的丰富来源。(请注意,这些评论和批评适用于支持SQL样式NULL的任何系统,而不仅限于SQL Server。)”
NULL作为吸毒成瘾:
(186/187)
在本书的其余部分中,我会敦促您不要使用它们,这似乎是矛盾的,但事实并非如此。将NULL视为毒品;正确使用它会为您工作,但是滥用它可能会毁了一切。最好的策略是在可能的情况下避免NULL,并在必要时正确使用它们。
我在这里的唯一反对意见是“正确使用它们”,这与特定的实现行为严重地相互作用。
6.5.1子查询谓词中的NULL(191/192)
人们忘记了子查询经常隐藏带有NULL的比较。考虑以下两个表:
...
结果将为空。这是违反直觉的,但却是正确的。
(分隔器)
6.5.2标准SQL解决方案(193)
SQL-92通过添加以下形式的新谓词解决了一些3VL(三值逻辑)问题:
<搜索条件> IS [否]是| 假| 未知
但是UNKNOWN本身就是问题的根源,因此下文引用的CJ Date在第4.5章中推荐。在SQL中避免空值:
- 请勿在任何情况下使用关键字UNKNOWN。
阅读UNKNOWN上的“ ASIDE”,该链接也在下面链接。
6.8 NULL和主机语言(194)
但是,您应该知道必须将NULL传递给主机程序时如何处理它们。没有定义嵌入的标准宿主语言不支持NULL,这是避免在数据库模式中使用它们的另一个很好的理由。
(分隔器)
6.9 NULL的设计建议(195)
最好在所有列上声明所有基表都具有NOT NULL约束。NULL使不懂SQL的人感到困惑,并且NULL代价很高。
反对意见:NULL甚至会使熟知SQL的人感到困惑,请参阅下文。
(195)
在外键中应避免为NULL。SQL允许这种“疑问的好处”关系,但是它可能导致涉及联接的查询中的信息丢失。例如,给定库存中的零件号代码,而Orders表将其称为FOREIGN KEY,则获取具有NULL的零件清单时将遇到问题。这是强制性关系;您不能订购不存在的零件。
(分隔器)
6.9.1避免主机程序中的NULL(197)
您可以避免使用某些编程规则将NULL从主机程序放入数据库中。
...
- 确定丢失的数据对编程和报告的影响: 带NULL的数字列是一个问题,因为使用聚合函数的查询可能会产生误导性的结果。
(分隔器)
(227)
空集的SUM()始终为NULL。使用此技巧时,最常见的编程错误之一是编写可能返回多个行的查询。如果您没有考虑,您可能将最后一个示例写为:...
(分隔器)
10.1.1 NULL的来源(242)
重要的是要记住在哪里可以出现NULL。它们不仅仅是列中的可能值。空集上的聚合函数,OUTER JOIN,带有NULL的算术表达式以及OLAP运算符均返回NULL。这些构造通常在VIEW中显示为列。
(分隔器)
(301)
当您尝试将IN谓词转换为EXISTS谓词时,会发现NULL的另一个问题。
(分隔器)
16.3 ALL谓词和极值函数(313)
首先,这两个谓词在SQL中是不同的,这与直觉相反:
...
但是,您必须记住极值函数的规则-在返回较大或最小值之前,它们会丢弃所有NULL。ALL谓词不会丢弃NULL,因此您可以在结果中获取它们。
(分隔器)
(315)
但是,标准中的定义用否定词表示,因此NULL带来了疑问。...
如您所见,最好避免在UNIQUE约束中使用NULL。
讨论GROUP BY:
将NULL视为彼此相等,并形成自己的组。然后,将每个组缩小为新结果表中的一行,以替换旧的结果表。
这意味着对于GROUP BY子句,NULL = NULL不会像3VL中那样评估为NULL,而是评估为TRUE。
SQL标准令人困惑:
ORDER BY和NULL(329)
是否将排序键值NULL视为大于或小于非NULL值是实现定义的,但是...
...有一些SQL产品可以做到这两种方式。
在1999年3月,克里斯·法拉尔(Chris Farrar)从他的一位开发人员那里提出了一个问题,促使他研究了我认为我理解的SQL标准的一部分。克里斯发现规范的一般理解与实际措词之间存在一些差异。
等等。我认为Celko够了。
SQL NULL上的CJ日期
CJ Date关于NULL更彻底:避免在SQL句点中使用NULL。实际上,他的SQL和关系理论的第4章:如何编写准确的SQL代码标题为“没有重复,没有NULL”,其子章“ 4.4 NULL有 什么问题?” 和“ 4.5在SQL中避免为空”(链接:感谢Google Books,您可以在线阅读某些页面)。
Fabian Pascal关于SQL NULL
从其数据库管理中的实际问题-思维从业者的参考(网上未摘录,对不起):
10.3实际含义
10.3.1 SQL空值
... 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
没有价值。
(NULL = NULL) -> FALSE
。引用文档的内容ANSI_NULLS
:“当指定为ON时,所有与空值的比较都将得出UNKNOWN。当指定了OFF时,如果两个值都为NULL,则将非UNICODE值与空值的比较都
也许要看情况,但是我认为大多数操作都以NULL作为操作数NULL=NULL
来进行评估NULL
。
仅仅因为您不知道什么是两件事,并不意味着它们是相等的。如果您想到NULL
“ NULL”(字符串),那么您可能想要一个不同的相等性测试,例如Postgresql的IS DISTINCT FROM
ANDIS NOT DISTINCT FROM
表达式
IS DISTINCT FROM
表达式表达式
IS NOT DISTINCT FROM
表达式对于非空输入,
IS DISTINCT FROM
与<>
运算符相同。但是,如果两个输入均为null,则返回false,如果只有一个输入为null,则返回true。类似地,IS NOT DISTINCT FROM
与=
非空输入相同,但是当两个输入均为空时,它返回true,而只有一个输入为空时,它返回false。因此,这些构造有效地充当空值是正常数据值,而不是“未知”。
至少可以说,NULL的概念值得怀疑。Codd在上下文中介绍了关系模型和NULL的概念(并提出了不止一种NULL!)。但是,关系理论自Codd的原始著作以来就已经发展起来:他的一些提议此后被舍弃(例如主键)其他人(例如theta运算符)从未流行。在现代关系理论(我应该强调的是真正的关系理论)中,NULL根本不存在。参见第三宣言。http://www.thethirdmanifesto.com/
SQL语言存在向后兼容的问题。NULL进入了SQL,我们一直坚持下去。可以说,NULL
SQL的实现存在缺陷(SQL Server的实现由于其ANSI_NULLS
选项而使事情变得更加复杂)。
我建议避免在基表中使用NULLable列。
尽管也许我不应该被吸引,但我只是想断言自己对NULL
SQL的工作方式的更正:
NULL
= NULL
计算为UNKNOWN
。
UNKNOWN
是一个逻辑值。
NULL
是一个数据值。
这很容易证明,例如
SELECT NULL = NULL
在SQL Server中正确生成错误。如果结果是一个数据值,那么我们期望看到NULL
,正如这里的一些答案(错误地)表明我们会那样。
UNKNOWN
分别在SQL DML和SQL DDL中对逻辑值进行不同的处理。
在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);
在INSERT
成功此行,即使CHECK
条件解析NULL = NULL
。这是由于在SQL-92(“ ANSI”)标准中定义的:
11.6表约束定义
3)
如果表约束是检查约束定义,则令SC为紧接在约束约束定义中的搜索条件,令T为包含在相应表约束描述符中的表名。当且仅当不满足表约束
存在(选择*从哪里(SC))
是真的。
按照逻辑再次仔细阅读。
用简单的英语来说,我们在上面的新行中给出了关于存在UNKNOWN
和被允许通过的“疑问的好处” 。
在SQL DML中,WHERE
子句的规则更容易遵循:
搜索条件应用于T的每一行。where子句的结果是T的那些行的表,这些条件的搜索条件的结果为true。
用简单的英语将评估UNKNOWN
结果中的行从结果集中删除。
在technet上,有一个很好的解释说明空值如何工作。
Null表示未知。
因此布尔表达式
值=空
不会计算为false,而是计算为null,但是如果这是where子句的最终结果,则不会返回任何内容。这是一种实用的方法,因为很难想象返回null。
了解以下内容非常有趣且非常重要:
如果在查询中
where (value=@param Or @param is null) And id=@anotherParam
和
然后
“ value = @ param”评估为null
“ @param为null”评估为true
“ id = @ anotherParam”评估为true
因此要评估的表达式变为
(null或true)和true
我们可能会倾向于认为这里的“ null或true”将被评估为null,因此整个表达式将变为null,并且该行将不返回。
事实并非如此。为什么?
因为“ null Or true”的计算结果为true,这是非常合逻辑的,因为如果一个操作数对Or运算符为true,则无论另一个操作数的值如何,该操作都将返回true。因此,另一个操作数未知(空)并不重要。
因此,我们最终有了true = true,因此将返回该行。
注意:使用“ null或true”评估为true相同的清晰逻辑,“ null And true”评估为null。
更新:
好的,只是为了使它完整,我也想在这里添加其余的内容,这与上面的内容相比非常有趣。
“ null或false”评估为null,“ null和false”评估为false。:)
当然,逻辑仍然像以前一样不言而喻。
答案似乎都是从CS的角度出发的,所以我想从开发人员的角度来补充。
对于开发人员,NULL非常有用。这里的答案说NULL表示未知,也许在CS理论中是正确的,不记得了,已经有一段时间了。但是,在实际开发中,至少以我的经验来看,这种情况发生的时间约为1%。其余的99%用于值不是UNKNOWN但未知的情况。
例如:
Client.LastPurchase
,适用于新客户。这不是未知数,已知他还没有购买。
映射树结构时,根通常会具有Parent = NULL
还有很多...
我确定大多数开发人员在某个时候都写了WHERE value = NULL
,没有得到任何结果,这就是他们学习IS NULL
语法的方式。只要看看这个问题和相关链接有多少票即可。
SQL数据库是一种工具,应以最易于用户理解的方式设计它们。
NULL不等于任何东西,甚至不等于本身。我个人了解NULL行为的解决方案是尽可能避免使用它:)。
混淆是由使用NULL引起的间接(抽象)级别引起的。
回到“圣诞树下是什么”的类比,“未知”描述了有关框A中内容的知识状态。
因此,如果您不知道Box A中的内容,则说它是“未知”,但这并不意味着“ Unknown”位于该框中。盒子里有未知以外的东西,可能是某种物体,或者盒子里什么也没有。
同样,如果您不知道方框B中的内容,则可以将有关内容的知识状态标记为“未知”。
因此,这里有一个关键点:您对Box A的了解程度与您对Box B的了解程度相同。(在两种情况下,您的知识状态都是“未知”或“我不知道盒子里有什么”。)但是盒子中的内容可能相等,也可能不相等。
回到SQL,理想情况下,只有知道值之后才可以比较值。不幸的是,描述缺乏知识的标签存储在单元格本身中,因此我们很想将其用作值。但是我们不应该将其用作值,因为它会导致“当我们不知道Box A中的内容和/或我们不知道Box B中的内容时,Box A的内容等于Box B的内容。 (从逻辑上讲,“如果我不知道方框A中的内容,如果我不知道方框B中的内容,那么方框A中的内容=方框B中的内容”的含义是错误的。)
是的,死马。
MSDN上有一篇很好的描述性文章,介绍了null及其所引起的三种状态逻辑。
简而言之,SQL92规范将NULL定义为unknown,并且在以下运算符中使用的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在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
null
,学习理解它或只是更改表以具有int类型并更新列。
您为政府登记有关公民的信息工作。这包括该国每个人的身份证。大约40年前,一个孩子被留在教堂的门口,没人知道他们的父母是谁。此人的父亲ID为NULL
。存在两个这样的人。计算与至少一个其他人(是兄弟姐妹的人)共享同一父亲ID的人。你也算这两个吗?
答案是否定的,你不是,因为我们不知道他们是否是兄弟姐妹。
假设您没有NULL
选择,而是使用一些预定的值来表示“未知”,也许是一个空字符串或数字0或*字符,等等。那么您的查询中将带有* = * ,0 = 0和“” =“”等。这不是您想要的(按照上面的示例),而且您可能经常忘记这些情况(上面的示例是普通日常思维之外的一个清晰的例子) ),那么您需要为您记住的语言NULL = NULL
是不正确的。
必要性是发明之母。
只是其他精彩答案的补充:
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