mysql中null是缺失值标记,不等于任何值(包括自身),where条件必须用is null/is not null;=、!=等比较操作均无效;coalesce/ifnull可安全替换null;group by和order by中null默认归为一组且排最前;not in遇null会导致结果为空,应改用not exists或排除null。

IS NULL 不能用 = NULL 替代
MySQL 里 NULL 不是值,而是“缺失值”的标记,所以它不等于任何东西——包括它自己。写 WHERE column = NULL 永远不成立,结果永远为空。
正确写法只有 IS NULL 或 IS NOT NULL:
SELECT * FROM users WHERE email IS NULL;
-
= NULL、NULL、!= NULL全部无效,SQL 标准规定它们都返回UNKNOWN,被WHERE当作假值过滤掉 - 部分 ORM(比如早期 Django)会自动把
field__isnull=True翻译成IS NULL,但手写 SQL 时绝不能偷懒写等号 - 如果字段加了索引,
IS NULL在大多数情况下仍能走索引(InnoDB 支持对NULL值建立 B+ 树索引)
COALESCE 和 IFNULL 处理 NULL 输出
查询结果里直接展示 NULL 往往不友好,需要替换成默认值,这时候别硬写 CASE WHEN x IS NULL THEN 'N/A' ELSE x END ——有更简洁的函数。
COALESCE 是标准 SQL 函数,接受多个参数,返回第一个非 NULL 的值;IFNULL 是 MySQL 特有,只支持两个参数,性能略高一点:
SELECT COALESCE(phone, mobile, '未提供') AS contact FROM customers;
-
COALESCE(a, b, c)等价于IFNULL(a, IFNULL(b, c)),但可读性更好 - 注意类型隐式转换:
IFNULL(123, 'abc')会把整数转为字符串,可能影响排序或计算,建议保持前后类型一致 - 所有参数都会被求值,哪怕前面已经非
NULL—— 所以避免在第二参数放耗时函数(如子查询)
GROUP BY 和 ORDER BY 中 NULL 的行为
MySQL 默认把所有 NULL 归为同一组,排序时默认排在最前面(升序),这点和 PostgreSQL 一致,但和 Oracle 不同(Oracle 把 NULL 排最后)。
如果业务要求 NULL 排末尾,得显式控制:
SELECT region, COUNT(*) FROM sales GROUP BY region ORDER BY region IS NULL, region;
-
ORDER BY region IS NULL返回0(非空)或1(空),升序就让非空先出,再配合region二级排序 -
GROUP BY里如果有多个NULL字段,它们会被合并统计,不会拆成多行 —— 这是预期行为,不是 bug - 使用
ROLLUP时,NULL代表小计/总计行,别误以为是脏数据
NOT IN 子查询遇到 NULL 就全失效
这是线上事故高发点:NOT IN 后面的子查询只要返回任意一个 NULL,整个条件就变成 UNKNOWN,结果集直接为空。
例如:SELECT name FROM users WHERE id NOT IN (SELECT user_id FROM logs),如果 logs.user_id 有 NULL,这条语句查不到任何用户。
- 根本原因是
a NOT IN (1, 2, NULL)等价于a != 1 AND a != 2 AND a != NULL,最后一项恒为UNKNOWN,整个表达式也为UNKNOWN - 安全替代方案:用
NOT EXISTS(推荐)或显式排除NULL:NOT IN (SELECT user_id FROM logs WHERE user_id IS NOT NULL) - 检查子查询字段是否允许
NULL,比修复 SQL 更治本 —— 日志表的user_id本就不该为NULL
NULL 的麻烦不在语法难记,而在它悄无声息地改变逻辑真假值。尤其在组合条件、子查询、聚合场景下,一个没意识到的 NULL 就能让结果少一半甚至全丢。上线前用 IS NULL 主动探查关键字段,比事后 debug 快得多。











