PostgreSQL使用NOT IN过滤数据未返回预期空值行问题
问题根因
SQL采用三值逻辑(TRUE/FALSE/UNKNOWN),与常规编程语言的二值逻辑存在明显差异:
- 任意值和NULL做等值、不等值比较时,结果永远是UNKNOWN,不会返回TRUE或FALSE。
- WHERE子句只会保留判断结果为TRUE的行,结果为UNKNOWN或FALSE的行都会被排除。
- 你编写的
letpos NOT IN ('0', '(!)','NA','N/A')本质等价于串联的多个不等值判断:
letpos <> '0' AND letpos <> '(!)' AND letpos <> 'NA' AND letpos <> 'N/A'
- 表中id=3、id=6对应的letpos字段实际存储的是NULL值(表格里的空白展示是NULL的默认显示效果,并非空字符串
''),上述每一段比较的结果都是UNKNOWN,整个WHERE条件最终不会判定为TRUE,因此这两条记录会被直接过滤,与你实际查询返回id=1、2的结果完全匹配。
修正方案
按照你的预期需要保留letpos为NULL的记录,直接将NULL场景的判断补充到WHERE条件中即可:
SELECT * FROM dump WHERE letpos NOT IN ('0', '(!)','NA','N/A') OR letpos IS NULL;
排查提示:如果需要确认letpos字段的实际存储类型(到底是NULL还是空字符串),可以执行如下校验语句:
SELECT id, letpos, (letpos IS NULL) AS is_null_flag, (letpos = '') AS is_empty_str_flag FROM dump;如果id=3、id=6对应的is_null_flag为1、is_empty_str_flag为0,就可以完全确认是NULL值的比较规则导致的过滤异常。
内容的提问来源于stack exchange,提问作者user2926497
相关产品推荐
相关产品推荐

