数据库中并不是只有: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进阶教材》,仅做笔记。一部分是自己理解,欢迎指出不对的地方。