三值逻辑和NULL

数据库中并不是只有:true/false 还有一种值叫 ‘不确定(unknown) null ’ 不确定会带来一系列的陷阱。

一、对null的判断为何不能是 ‘=’、‘>’、'<' 、'<>'、 一系列的判断呢?

答: 首先NULL不是值,它是对不确定的表示。判断运算符是对值进行判断的,对null使用比较运算符最终结果都是 unknown, 查询不出任何数据。所以说对 ‘null’ 判断只有使用 ‘is null’/'is not null'

看下面的知识前,请先记住 在 'and' 语句中 unknown优先级大于true ,在 'or' 语句中 true优先级大于unknown。

如:现在有值 a=2 、b=5 、c=null

1:a<b and b>c

2:a>b or b<c

3:a<b or b<c

答案是: 1 unknown· 、2 unknown 、 3  true

第一点: 在我们现实世界中有这样的一个真命题 : 约翰的年龄是20岁,或者不是20岁,二者必居其一。

select age from demo where age=20 or age<>20

这是现实世界中的二指逻辑,但是在数据库中并行不通。

现有情况 约翰的年龄不明确为 :null  现在的sql语句就变成了:

1: select age from demo where age=NULL or age<>NULL

2:select age from demo where age=unknownor age<>unknownor

之前说过 在 or 中 出现 unknownor ,true优先级最高,但是这里没有true 所以返回数据为空

第二点:CASE 表达式和NULL

null 在 case 表达式中的陷阱:

case age when 1 then 'O' when NULL then 'X' end;

这句表达中‘X’ 永远都出不来,因为上面语句最终变成 age=null 无法返回ture 所以‘X’ 不会出现。

可以改写为:

case when age=1 then 'O' when age is NULL then 'X' end;

切记不能把NULL当成值去运算。

第三点:NOT IN() 和 NOT EXISTS() 不是等价的

首先not in() 是把其中值变成了 and 语句组装 的简写,如 age NOT IN(1,2, 3 ) 最终变成  age<>1 and age<> 2 and age<>3 。若现在把 age NOT IN(1,2, 3) 中 3 换为了null 现在 age<>1 and age<> 2 and age<>null  最后不能得出任何结果值。

NOT EXISTS() 只会返回true和false 所以会避免返回not in()的情况 ,会排出null值返回正确的值

第四点:限定谓词和null

如在A班中找出比B班所有人年龄大的学生。

select  name from A where age> all(select age from B) ,若B表中age都明确(不是NULL)则没毛病,一旦有NULL 则这条sql语句不会返回任何数据。应为最终都把all中的所有 age 用 'and' 连接起来了(select  name from A where age>19 and age>22 and age>null) ,之前说过and 中 对null算数比较 是不会返回值得,所以....明白?

第五点:限定谓词和极值函数不是等价

首先回到第四点(在A班中找出比B班所有人年龄大的学生。) 另一种写法:

select  name from A where age>(select max(age) from B)

这就避免了age不明确的情况?(max(age)会排出为age为null的情况再计算),但是,真的是这样吗?

现有一种情况 B 班没有学生!!! 上面的sql语句就变成了这样:select  name from A where age>(null) ,不会返回任何数据。

极值函数在输入为空集(空表)时,会返回null 。

其实在这里我们希望的是为空集时返回A表中所有数据。All() 函数就避免了这样的情况,或者说用COALESCE函数将极值函数返回的NULL值替换成合适的值。

第六点:聚合函数和null

。除count()聚合函数外,其他的所有聚合函数在为空集时返回的都是null 。在sql语句中:

select  name from A where age>(select max(age) from B)  , where 条件后永远是nuknown 不会返回任何数据,这样的情况只有两种方法可以解决:要嘛把null该成具体的值,要么接受null。

聚合函数的陷阱是由函数自带的,仅仅只靠在列上加 not null 是无法从根本上消除的,因此我们在编写sql时需要多加注意。

总结:

一、NULL不是值

二、因为NULL不是值,所以不能对其用谓词

三、对NULL使用谓词的结果是:unknown

四、unknown 加入sql逻辑运算时,会带来意想不到的后果(最前面标红字体)

最后说明:想要解决NULL带来的问题,最佳方法是在表中添加not null来尽力排出NULL,这样就能回到二值逻辑的世界(虽然不能完全回到二值逻辑)。

内容多来自 《SQL进阶教材》,仅做笔记。一部分是自己理解,欢迎指出不对的地方。


版权声明:本文为wangzaza原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。