NOT IN空值题的常见误区,是把“没有找到相等值”直接当成“确定不在集合中”。右侧存在NULL时,没有相等命中的比较结果可能是未知,WHERE不会保留它。知英教育先用三个非空编号逐行计算,再讨论没有相等记录的另一种表达。

三行候选、两行排除数据

自编Candidate表id依次11、12、13,均明确非NULL;Closed表id为12、NULL。查询SELECT id FROM Candidate WHERE id NOT IN (SELECT id FROM Closed);。编号12有相等命中,结果为假。11和13不等于已知的12,但与NULL的比较不能确定,整体为未知。最终没有输出行,并不代表原表没有记录。

把未知写出来,不偷偷替换成假

对11,本例可理解为(11<>12) AND (11<>NULL):第一项真,第二项未知,结果仍未知。编号12包含一个明确为假的不等比较,整体为假。WHERE只保留真,假和未知都被过滤,但它们不是同一个逻辑值。

知英教育建议在NOT IN空值练习旁标出真、假、未知。NULL不是0,也不是空字符串;右侧一行NULL更不是右侧完全无行。若Closed为空,本文三个非空编号全部保留;若只删除NULL行,留下12,结果为11、13。这是改变输入后分别推导,不是同一查询随机改变结果。

右表空集与一行NULL对三个非空编号的NOT IN判断不同
本文外侧编号明确非空,两种输入须分别推导。

NOT EXISTS怎样表达没有相等匹配

对原始数据可写SELECT c.id FROM Candidate c WHERE NOT EXISTS (SELECT 1 FROM Closed x WHERE x.id=c.id);。11没有任何行使关联条件为真,保留;12有真匹配,排除;13没有真匹配,保留,得到11、13。SELECT 1里的1不是计数,EXISTS只看子查询是否返回至少一行。

两种写法并非无条件等价。如果外表编号也允许NULL,上面的相关等值条件不会为它找到真匹配,NOT EXISTS可能保留外侧空值记录,而NOT IN对非空右集可能为未知。必须先说明是否保留外侧NULL。本例刻意约定外侧非空,避免漏掉这个边界;也不根据小表断言某种写法在所有数据库都更快。

相关NOT EXISTS逐项寻找等值匹配,保留11和13
先说明没有相等记录的意图,再判断查询形式。

复盘时保留每一行的比较依据

检查NOT IN空值问题,先保留原始两表,再写相等命中、未知比较与WHERE过滤结果。至少区分右表为空、右表只有NULL、右表既有匹配又含NULL三种输入。把子查询返回行数和返回值是否为空分开,也能理解为何EXISTS(SELECT NULL)在确实返回一行时仍为真。

知英教育可协助梳理SQL语义。查看软件设计师学习内容,通过咨询入口说明哪些列允许为空及自己的判断;请用自编数据。本文不是考试原题,不作通过承诺。

资料来源:PostgreSQL 18官方文档:EXISTS、IN与NOT IN的NULL规则。核对日期:2026年10月22日。编号和表均为原创教学数据。