sql中where条件不能用= null或!= null,必须用is null或is not null;join/group by中null被视为相同值;coalesce/case可辅助但不推荐替代is null;索引对is null支持因数据库而异;order by中null排序需显式控制。

WHERE条件里不能用 = NULL 或 != NULL
SQL里NULL不是值,而是“缺失值”的标记,所以任何与NULL的等值比较(比如= NULL或!= NULL)结果都是UNKNOWN,不会被WHERE选中——哪怕字段真是NULL,这行数据也查不到。
实操建议:
- 查
NULL必须用IS NULL,例如:SELECT * FROM users WHERE email IS NULL - 查非
NULL必须用IS NOT NULL,例如:SELECT * FROM users WHERE email IS NOT NULL - 别写
email = NULL或email NULL,它们永远不返回数据(即使表里全是NULL) - 在
JOIN或GROUP BY中,NULL会被当作相同值处理,但这是另一套逻辑,和WHERE无关
COALESCE或CASE可以辅助判断,但别滥用
有时你想把NULL转成某个默认值再参与比较(比如统计“有邮箱或没邮箱但手机号有效”的用户),这时可以用COALESCE或CASE,但要注意它不改变原始NULL语义,只是临时替换。
实操建议:
-
COALESCE(email, 'missing@null') = 'missing@null'能间接筛选NULL,但不如直接写email IS NULL清晰、高效 - 想组合多个字段判空,比如“email或phone至少一个非空”,写成:
WHERE email IS NOT NULL OR phone IS NOT NULL,别用COALESCE(email, phone) IS NOT NULL——后者在两个都为NULL时才NULL,但语义易错且无法走索引 -
CASE WHEN email IS NULL THEN 0 ELSE 1 END = 0纯属绕路,直接用email IS NULL
索引对IS NULL查询的支持因数据库而异
大多数主流数据库(PostgreSQL、MySQL 8.0+、SQL Server)支持在普通B-tree索引中高效定位IS NULL,但前提是该字段允许NULL且索引未被定义为NOT NULL约束。
实操建议:
- PostgreSQL:单列索引天然支持
IS NULL,执行计划里看到Index Scan using ... on ... (cost=... rows=...) (actual rows=...)就说明走了索引 - MySQL:InnoDB对
IS NULL能用索引,但MyISAM不行;如果字段有NOT NULL约束,IS NULL条件会直接返回空结果,优化器甚至可能跳过扫描 - 避免给常量加索引:比如
CREATE INDEX idx_status_null ON orders ((status IS NULL))(PostgreSQL表达式索引)仅在极少数场景有用,多数时候是过度设计
ORDER BY里NULL排在哪取决于数据库和显式设置
ORDER BY col ASC时,NULL默认排最前(PostgreSQL)还是最后(MySQL、SQL Server)不统一,容易导致分页或展示逻辑出错。
实操建议:
- 明确控制顺序:用
ORDER BY col ASC NULLS FIRST(PostgreSQL)或ORDER BY IF(col IS NULL, 1, 0), col ASC(MySQL) - SQLite不支持
NULLS FIRST/LAST,只能靠CASE模拟:ORDER BY CASE WHEN col IS NULL THEN 0 ELSE 1 END, col - 如果业务上
NULL代表“未知”或“未设置”,通常应排在末尾;若代表“最高优先级”,才放前面——这点必须和产品逻辑对齐,不能只看数据库默认行为
NULL判断看着简单,真正踩坑多在隐式转换、索引失效和跨库行为差异上。写完IS NULL后,最好用EXPLAIN看一眼执行计划,尤其当表数据量超过十万行时。










