SQL中NOT作用于空值安全等值判断的异常行为原因查询
问题成因分析
核心原因是SQL遵循三值逻辑(TRUE/FALSE/UNKNOWN),而非常规编程语言的二值布尔逻辑,NULL参与的等值比较会返回UNKNOWN而非TRUE或FALSE,结合CASE WHEN的执行规则就会出现不符合预期的结果。
具体逻辑拆解
- 基础规则先明确:
- 任意非NULL值和NULL用
=比较时,结果均为UNKNOWN - 逻辑运算中
NOT UNKNOWN的返回值依旧是UNKNOWN - CASE WHEN子句仅当判断条件明确为
TRUE时才会执行THEN分支,只要条件为FALSE或UNKNOWN都会进入ELSE分支
- 任意非NULL值和NULL用
- 触发异常的场景为「a、b其中一个为NULL,另一个不为NULL」的行,我们以插入的第二行
a='v', b=NULL为例计算:- 先计算公共判断逻辑
(a = b OR (a IS NULL AND b IS NULL)):a = b返回UNKNOWN(a IS NULL AND b IS NULL)返回FALSE- OR运算后整体结果为UNKNOWN
- 第一个CASE的判断条件为UNKNOWN,进入ELSE分支,
nullSafeEqual返回false - 第二个CASE的判断条件为
NOT(UNKNOWN),结果依旧是UNKNOWN,同样进入ELSE分支,NotNullSafeEqual也返回false
此时两个字段返回值相同,和你预期的「完全取反」不符。
- 先计算公共判断逻辑
修正方案参考
如果要实现完全取反的效果,可以直接对第一个CASE的判断逻辑结果反向输出,避开三值逻辑的影响:
SELECT a, b, CASE WHEN (a = b OR (a IS NULL AND b IS NULL)) THEN 'true' ELSE 'false' END "nullSafeEqual", CASE WHEN (a = b OR (a IS NULL AND b IS NULL)) THEN 'false' ELSE 'true' END "NotNullSafeEqual" FROM t
也可以使用对应数据库自带的空安全比较运算符简化逻辑,比如MySQL的<=>、PostgreSQL的IS NOT DISTINCT FROM,都可以直接实现空安全的等值判断,不需要手动写NULL判断逻辑。
内容的提问来源于stack exchange,提问作者fbehrens
相关产品推荐
相关产品推荐

