SQL查询:IS NULL条件返回非空行及AND逻辑有效性疑问
这问题我之前排查过好几次,大概率是SQL运算符优先级在偷偷搞事情!
核心原因:AND比OR优先级高
你写的原始SQL如果没给start date > 当前日期 OR end date > 当前日期加括号的话,数据库会按照默认优先级执行:先处理end date > 当前日期 AND whitepaper IS NULL,再把这个结果和start date > 当前日期做OR运算。
举个例子,假设你的SQL是这样的:
SELECT * FROM your_table WHERE start_date > CURRENT_DATE OR end_date > CURRENT_DATE AND whitepaper IS NULL;
实际执行逻辑等价于:
SELECT * FROM your_table WHERE start_date > CURRENT_DATE OR (end_date > CURRENT_DATE AND whitepaper IS NULL);
这就意味着,所有start_date > 当前日期的行——不管whitepaper是不是NULL——都会被查询出来,这就是你看到不符合预期结果的原因。
为什么换成whitepaper IS NOT NULL时看起来正常?
这大概率是巧合:你的数据集中,所有start_date > 当前日期的行刚好whitepaper都不为NULL,所以执行结果看起来都是符合whitepaper IS NOT NULL的,但其实SQL逻辑依然是错的——如果哪天出现start_date > 当前日期且whitepaper为NULL的行,这部分数据也会被错误地查出来。
正确的写法
给OR的两个条件加上括号,明确让数据库先判断“日期条件”,再和“whitepaper为NULL”做AND运算:
SELECT * FROM your_table WHERE (start_date > CURRENT_DATE OR end_date > CURRENT_DATE) AND whitepaper IS NULL;
这样就能严格筛选出:满足「start或end日期大于当前」并且「whitepaper列为NULL」的行,不会再出现不符合预期的数据。
额外提醒:SQL的三值逻辑
虽然这次问题的核心是优先级,但还是要提一句:SQL里NULL和任何值比较都会返回UNKNOWN,只有用IS NULL/IS NOT NULL才能准确判断NULL状态——不过你这里已经用对了,只是优先级坑了你~
内容的提问来源于stack exchange,提问作者ii iml0sto1

