三值逻辑指的是SQL总的Boolean类型有三个真值,分别是true
、false
和unknow
。当值缺失时会使用NULL这个标识符来标识,而对NULL使用比较谓词时其结果永远是unknow,例如1 = null 返回unknow,1 > null 返回unknow,null = null也返回unknow。
三值优先级:
在AND中 FALSE > unknow > TRUE
在OR中 TRUE > unknow > FALSE
WHERE子句只会筛出返回为TRUE的记录
在SQL中NULL并不是一个值,而是一个标识符,表示该值不知道。而谓词表达式只能作用于值,当谓词表达式作用于NULL标识符时取代报错的是返回unknow这个布尔值。
因为NULL不是值所以不能用谓词来判断是否为NULL,只能通过IS NULL来判断该值是否为NULL,更加让人混淆的是IS TRUE也是合法的,确实有点尴尬。
所以说来说去在语法上并没有直接证据表明在SQL中NULL是一个特殊存在,它不是值。
三值逻辑带来的影响
直接影响是排中律不成立
把命题和它的否命题通过‘或者’连接而成的命题全都是真命题”这个命题在二值逻辑中被称为排中律(law of excluded middle)
这个人是20岁或者不是20岁在三值逻辑下不成立,因为还有一种可能是不知道。
-- 查询年龄是 20 岁或者不是 20 岁的学生
SELECT *
FROM Students
WHERE age = 20 OR age <> 20;
若想筛出全部,需要做如下修改。
-- 查询年龄是 20 岁或者不是 20 岁的学生
SELECT *
FROM Students
WHERE age = 20 OR age <> 20 OR age IS NULL;
CASE表达式和NULL
CASE表达式和WHERE子句一样,只会返回TRUE的结果,所以unknow的引入也会对CASE表达式造成影响。
CASE WHEN col_1 = 1 THEN '○'
WHEN col_1 IS NULL THEN '×'
END
如上例,col_1
如果是NULL则只能通过col_1 IS NULL
来判断。
NOT IN 和 NOT EXISTS不等价
age NOT IN (22, 23, NULL);
转换为
age != 22 AND age != 23 AND age != NULL -- 返回unknow
NOT IN
的入参集合里面如果有NULL,那么即使age
等于22也无法筛出该条记录。而IN
则不会有这个问题,因为IN
的拆解是OR
,在OR
中TRUE
的优先级高于unknow
。
而NOT EXISTS的返回会过滤掉NULL值
NOT EXISTS (SELECT * from Students WHERE age != 22 AND age != 23 AND age != NULL);
和没有值进行运算得到的unknow,也可以表示"不知道UNKNOW"和"不适用not applicable, inapplicable"这两种,例如:
戴墨镜的人眼睛是什么颜色?不知道表示的是满足某种条件时可以知道
冰箱的眼睛是什么颜色?不知道表示的是不适用,因为冰箱没有眼睛,无论满足什么条件都无法知道,这个问题没有意义
除了WHERE和CASE会自动过滤掉unknow的数据,在SELECT子句中使用的函数例如,COUNT、MAX等函数也会自动过滤掉NULL。
参考
SQL 进阶教程 (第2版)[日]MICK - 人民邮电出版社