必须用is null而非等号判断null,因为null是缺失值标记而非值,= null恒返回unknown(被where视为false),查不到任何数据;is null是sql标准谓词,语义明确且跨库兼容。

IS NULL 不能用等号判断,必须用专门操作符
SQL 里 NULL 不是值,而是“缺失值”的标记,所以 = NULL 永远返回 FALSE 或 UNKNOWN,查不到任何数据。必须用 IS NULL(或 IS NOT NULL)来判断。
常见错误写法:WHERE column_name = NULL —— 这条语句不会报错,但结果永远为空。
-
WHERE column_name IS NULL是唯一标准写法 - 部分数据库(如 PostgreSQL)支持
column_name IS DISTINCT FROM NULL,但兼容性差,不推荐日常使用 - 在索引字段上用
IS NULL通常能走索引,但 MySQL 5.7 以前对IS NULL的索引优化较弱,建议升级或加覆盖索引
WHERE 和 HAVING 都能用 IS NULL,但语义完全不同
WHERE column IS NULL 是在分组前过滤原始行;HAVING COUNT(*) IS NULL 这种写法是错的——因为 HAVING 后面只能跟聚合结果或分组字段,而 COUNT(*) 永远是数字,不可能为 NULL。
- 想查“某分组内某个字段全为 NULL 的组”,得先用
GROUP BY,再配合HAVING MAX(column) IS NULL AND MIN(column) IS NULL(适用于该字段本身可空且无非空值) - 更稳妥的方式是:
HAVING COUNT(column) = 0,表示该组中column无非空值 - 注意:聚合函数如
SUM()、AVG()对全NULL输入会返回NULL,但COUNT(column)只统计非空,COUNT(*)统计所有行
JOIN 场景下 IS NULL 常用来识别“未匹配项”
左连接后右表字段为 NULL,是判断“左表有、右表无”的关键信号。比如查所有没下过单的用户:
SELECT u.id, u.name FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE o.user_id IS NULL;
这里必须用 o.user_id IS NULL,而不是 o.id IS NULL —— 因为如果 orders 表主键是自增 id,它永远不会为 NULL,哪怕没匹配上,o.id 也是 NULL,但语义不如外键字段清晰。
- 确保
ON条件里的关联字段类型一致,否则隐式转换可能导致NULL判断失效 - MySQL 在
STRICT_TRANS_TABLES模式下,对JOIN中类型不匹配的字段会报错,而非静默转成NULL - PostgreSQL 对
NULL比较更严格,LEFT JOIN后直接WHERE right_table.some_col IS NULL是最常用且安全的写法
IS NULL 和 COALESCE / NULLIF 的组合容易混淆
COALESCE(a, b) 返回第一个非 NULL 值;NULLIF(a, b) 在 a = b 时返回 NULL,否则返回 a。它们和 IS NULL 经常一起用,但目的不同。
- 想把空值转成默认值再判断?别嵌套:
COALESCE(column, 'N/A') = 'N/A'是错的——因为原值是NULL时,COALESCE返回'N/A',但字符串比较不是判断空值的本意 - 正确做法:先用
IS NULL过滤,再用COALESCE做展示层处理 -
NULLIF(column, '')把空字符串转成NULL后,才能统一用IS NULL处理,这在清洗脏数据时很常见 - 注意:Oracle 中空字符串等价于
NULL,但其他数据库不这样,跨库迁移时要特别小心
ORDER BY column 默认把 NULL 排最前(MySQL)或最后(PostgreSQL),不显式写 NULLS FIRST/LAST 就可能出偏差。










