Byr*_*ock 137 sql sql-server null
在SQL Server中,如果 nullParam=NULL
在where子句中,它总是计算为false.这是违反直觉的,并且给我带来了许多错误.我确实理解IS NULL
和IS NOT NULL
关键字是正确的方法.但是为什么SQL服务器会以这种方式运行?
Sco*_*vey 198
在这种情况下,将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'
Run Code Online (Sandbox Code Playgroud)
Nei*_*gan 124
弗兰克多大了?我不知道(null).
雪莉多大了?我不知道(null).
弗兰克和雪莉的年龄相同吗?
正确答案应该是"我不知道"(null),而不是"不",因为Frank和Shirley 可能是同一年龄,我们根本就不知道.
MaD*_*D70 26
在这里,我希望澄清我的立场.
这NULL = NULL
评估为FALSE
是错误的.黑客和先生正确回答NULL
.这就是原因.Dewayne Christensen在给Scott Ivey的评论中写信给我:
从12月开始,让我们使用一个季节性的例子.我在树下有两件礼物.现在,你告诉我是否有两个相同的东西.
它们可以是不同的,也可以是平等的,直到一个打开两个礼物,你才知道.谁知道?你邀请了两个彼此不认识的人,两人都给了你同样的礼物 - 很少见,但并非不可能§.
所以问题是:这两个UNKNOWN呈现相同(等于,=)?正确答案是:UNKNOWN(即NULL
).
这个例子的目的是为了证明 "..(false
或者null
,取决于你的系统).."是一个正确的答案 - 它不是,只有 NULL
在3VL中是正确的(或者你可以接受一个给出错误答案的系统吗? )
这个问题的正确答案必须强调这两点:
所以我重申:SQL没有任何好处强迫一个人解释相等的反身属性,这表明:
for any x, x = x
§§(用简单的英语:无论话语的世界如何,"事物"总是等于它自己).
..在3VL( ,TRUE
,).FALSE
NULL
人们的期望将符合2VL(TRUE
,FALSE
即使在SQL中对所有其他值也有效),即x = x
总是评估为 TRUE
x的任何可能值 - 没有例外.
另请注意,NULL是有效的" 非值 "(因为他们的辩护者假装它们),哪个可以作为关系变量的一部分指定为属性值(??).因此,它们是每种类型(域)的可接受值,而不仅仅是逻辑表达式的类型.
而这是我的观点:NULL
作为价值,是一个"奇怪的野兽".没有委婉语,我更愿意说:胡说八道.
我认为这个表述更清晰,更少争议 - 对不起我的英语水平很差.
这仅仅是一个的空值的问题.如果可能的话,最好完全避免它们.
§我们关注这里的价值观,所以这两个礼物总是两个不同的物体,这不是一个有效的反对意见; 如果你不相信我很抱歉,这不是解释价值和"对象"语义之间差异的地方(关系代数从一开始就有价值语义 - 参见Codd的信息原理;我认为一些SQL DBMS实现者不要甚至不关心常见的语义.
§§据我所知,这是一个被接受的公理(以某种形式或另一种形式,但总是以2VL的形式解释)因为古代而且正是因为如此直观.3VL(实际上是一个逻辑家族)是一个更近期的发展(但我不确定什么时候开始发展).
旁注:如果有人将底部,单元和选项类型作为尝试来证明SQL NULL的合理性,那么只有经过一次非常详细的检查才能说明我将如何使用NULL实现具有声音类型系统的SQL实现并最终澄清,什么是NULL(这些"值 - 不是很多值")确实是.
以下我将引用一些作者的话.任何错误或遗漏都可能是我的,而不是原作者.
Joe Celko关于SQL NULLs
我在这个论坛上经常引用Joe Celko.显然他在这里是一位备受尊敬的作家.所以,我对自己说:"他写的关于SQL NULL的内容是什么?他如何解释NULL很多问题?".我的一个朋友有一个电子书版本的Joe Celko的智能手机SQL:高级SQL编程,第3版.让我们来看看.
一,目录.最让我印象深刻的是提到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子查询中的NULLS谓词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
...
等等.它给我带来了"令人讨厌的特殊情况".
我将通过本书的摘录进入其中一些案例,并出于版权原因试图将自己限制在必要的范围内.我认为这些引用属于"合理使用"原则,他们甚至可以刺激购买这本书 - 所以我希望没有人会抱怨(否则我将需要删除大部分内容,如果不是全部的话).此外,出于同样的原因,我将不再报告代码片段.对于那个很抱歉.购买这本书,阅读有关数据推理的内容.
以下是括号内的页码.
NOT NULL约束(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 Date:
6 NULL:SQL中缺少数据(185)
在他们的书"Sybase和SQL Server指南"中,David McGoveran和CJ Date说:"这是作者的观点,而不是NULL,至少目前在SQL中定义和实现,比它们的价值要大得多,应该避免; 它们表现出非常奇怪和不一致的行为,可能是错误和混乱的丰富来源.(请注意,这些注释和批评适用于任何支持SQL样式NULL的系统,而不仅仅适用于SQL Server.)"
NULLs作为吸毒成瘾:
(187分之186)
在本书的其余部分,我将敦促你不要使用它们,这看似矛盾,但事实并非如此.将NULL视为药物; 正确使用它,它适用于你,但滥用它,它可以毁了一切.您最好的策略是尽可能避免使用NULL,并在必要时正确使用它们.
我在这里的唯一反对意见是"正确使用它们",它与特定的实现行为非常相互作用.
6.5.1子查询谓词中的NULLS(191/192)
人们忘记了子查询经常隐藏与NULL的比较.考虑这两个表:
...
结果将为空.这是违反直觉的,但是正确的.
(分隔器)
6.5.2标准SQL解决方案(193)
SQL-92通过添加表单的新谓词解决了一些3VL(三值逻辑)问题:
<搜索条件> IS [NOT] TRUE | FALSE | 未知
但是UNKNOWN本身就是问题的根源,所以CJ Date在下面引用的书中推荐给第4.5章.在SQL中避免空值:
- 不要在任何上下文中使用关键字UNKNOWN.
在UNKNOWN上阅读"ASIDE",也在下面链接.
6.8 NULL和主机语言(194)
但是,您应该知道在必须将NULL传递给宿主程序时如何处理NULL.没有为其定义嵌入的标准宿主语言支持NULL,这是避免在数据库模式中使用它们的另一个好理由.
(分隔器)
6.9 NULL的设计建议(195)
尽可能在所有列上声明所有基表的NOT NULL约束是个好主意.NULL会使不熟悉SQL的人感到困惑,而NULL则很昂贵.
异议:NULL甚至会让那些熟悉SQL的人感到困惑,见下文.
(195)
在FOREIGN KEY中应该避免使用NULL.SQL允许这种"怀疑的好处"关系,但它可能导致涉及连接的查询中的信息丢失.例如,给定Inventory中由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不会计算为NULL,如在3VL中,但它计算为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代码标题为"没有重复,没有NULLS",子章节 "4.4什么是空的错误?" 和"4.5避免SQL中的空白"(请点击链接:感谢Google Books,您可以在线阅读一些页面).
关于SQL NULL的Fabian Pascal
从数据库管理的实际问题 - 思维从业者的参考(没有在线摘录,抱歉):
10.3实际意义
10.3.1 SQL NULL
...... 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方法,因此,它们不仅能够解决这些问题,而且还会产生特定的实施问题,这些问题因产品而异.
这里的答案似乎都来自 CS 的角度,所以我想从开发人员的角度添加一个。
对于开发人员来说,NULL 非常有用。这里的答案说 NULL 意味着未知,也许在 CS 理论中这是真的,不记得了,已经有一段时间了。但在实际开发中,至少根据我的经验,这种情况发生的概率约为 1%。其他 99% 用于值不是未知但已知不存在的情况。
例如:
Client.LastPurchase
,对于新客户。这不是未知的,据了解他还没有进行购买。
在映射树结构时,根通常具有Parent = NULL
还有很多...
我相信大多数开发人员在某个时候写过WHERE value = NULL
,没有得到任何结果,这就是他们学习IS NULL
语法的方式。看看这个问题和相关问题有多少票。
SQL 数据库是一种工具,应该以用户最容易理解的方式设计它们。
仅仅因为你不知道两件事是什么,并不代表他们是平等的.如果你认为NULL
你想到"NULL"(字符串)那么你可能想要一个不同的测试,如Postgresql的IS DISTINCT FROM
ANDIS NOT DISTINCT FROM
http://www.postgresql.org/docs/8.4/static/functions-comparison.html
表达式IS DISTINCT FROM表达式
表达式IS NOT DISTINCT FROM表达式
对于非空输入,IS DISTINCT FROM与<>运算符相同.但是,如果两个输入都为null,则返回false,如果只有一个输入为null,则返回true.类似地,对于非空输入,IS NOT DISTINCT FROM与=相同,但是当两个输入都为空时返回true,而当只有一个输入为null时返回false.因此,这些构造有效地表现为null是正常数据值,而不是"未知".
在technet 上,对空值的工作方式有一个很好的解释。
Null 表示未知。
因此布尔表达式
值=空
不计算为 false,计算为 null,但如果这是 where 子句的最终结果,则不返回任何内容。这是一种实用的方法,因为很难想象返回 null。
了解以下内容很有趣且非常重要:
如果在查询中我们有
where (value=@param Or @param is null) And id=@anotherParam
Run Code Online (Sandbox Code Playgroud)
和
然后
"value=@param" 计算结果为 null
"@param is null" 计算结果为 true
"id=@anotherParam" 计算结果为 true
所以要评估的表达式变成
(null 或 true) 和 true
我们可能会认为这里的“null 或 true”将被评估为 null,因此整个表达式变为 null 并且不会返回该行。
事实并非如此。为什么?
因为“null Or true”的计算结果为true,这是非常合乎逻辑的,因为如果Or运算符的一个操作数为true,那么无论另一个操作数的值如何,该操作都将返回true。因此,另一个操作数未知(空)并不重要。
所以我们终于有了 true=true ,因此该行将被返回。
注意:“null 或 true”的计算结果为真,“null And true”的计算结果为 null,逻辑清晰。
更新:
好的,为了使它完整,我也想在这里添加其余的内容,与上述内容相比,这很有趣。
“null 或 false”计算结果为 null,“null And false”计算结果为 false。:)
逻辑当然还是和以前一样不言而喻。
MSDN 有一篇关于空值和它们产生的三种状态逻辑的很好的描述性文章。
简而言之,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
Run Code Online (Sandbox Code Playgroud)
至少可以说,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);
Run Code Online (Sandbox Code Playgroud)
该INSERT
行成功,即使CHECK
条件解析为NULL = NULL
。这是在 SQL-92(“ANSI”)标准中定义的:
11.6 表约束定义
3)
若表约束为校验约束定义,则设SC为校验约束定义中直接包含的搜索条件,T为对应表约束描述符中包含的表名;表约束不满足当且仅当
存在(从 T WHERE NOT (SC) 中选择 *)
是真的。
仔细阅读一遍,遵循逻辑。
用简单的英语,我们上面的新行给出了关于存在UNKNOWN
和允许通过的“怀疑的好处” 。
在 SQL DML 中,WHERE
子句的规则更容易遵循:
搜索条件应用于 T 的每一行。 where 子句的结果是 T 中搜索条件结果为真的那些行的表。
在简单的英语中,评估为的行UNKNOWN
将从结果集中删除。
因为NULL
意味着“未知值”并且两个未知值不能相等。
因此,如果按照我们的逻辑NULL
N\xc2\xb01 等于NULL
N\xc2\xb02,那么我们必须以某种方式告诉:
SELECT 1\nWHERE ISNULL(nullParam1, -1) = ISNULL(nullParam2, -1)\n
Run Code Online (Sandbox Code Playgroud)\n\n其中已知值-1
N\xc2\xb01 等于-1
N\xc2\xb02
归档时间: |
|
查看次数: |
105407 次 |
最近记录: |