GROUP BY中NULL值会被自动聚成一组,需在GROUP BY和SELECT中同步使用COALESCE(或IFNULL)替换为默认值,否则仅SELECT端转换无效;多字段或表达式均须分别包裹。
GROUP BY 中的 NULL 值不会被忽略,而是自动聚成一组——这是标准行为,不是 bug。但多数人误以为它“不参与分组”或“该被填掉”,结果写出 SELECT NVL(status, 'pending'), COUNT(*) FROM orders GROUP BY status 这类无效写法,导致 NULL 依然单独出一行。
必须让分组字段本身不含 NULL,而不是只在 SELECT 里转换。否则分组逻辑照旧,NVL 或 COALESCE 的结果只是显示用,对分组无影响。
GROUP BY 子句里得显式包裹:写成 GROUP BY COALESCE(status, 'unknown'),不是 GROUP BY status
IFNULL(status, 'unknown'),PostgreSQL/Oracle 用 COALESCE(status, 'unknown'),跨库迁移时这里必报错GROUP BY COALESCE(a, 'x'), COALESCE(b, 'y')
UPPER(name)),得对整个表达式套:GROUP BY COALESCE(UPPER(name), 'UNKNOWN')
这是最常踩的坑:同一组 NULL 数据,COUNT(*) 算的是行数,COUNT(status) 却返回 0——因为后者跳过所有 NULL 值。
COUNT(status),要写 COUNT(*) 或 SUM(CASE WHEN status IS NULL THEN 1 ELSE 0 END)
COUNT(NVL(status, 'x')) 没用:NVL 把 NULL 变成字符串后,COUNT 照样计数,结果和 COUNT(*) 一样COUNT(CASE WHEN status IS NULL THEN 1 END)
NULLS LAST 看起来干净,但 MySQL 5.7 及更早版本根本不认,直接报 ERROR 1064。
ORDER BY col NULLS LAST
ORDER BY IF(col IS NULL, 1, 0), col
NULLS LAST,但行为不稳定,建议统一用 IF 或 CASE 表达式兜底col 是字符串且用了 COLLATE,某些排序规则会覆盖 NULLS LAST,实际 NULL 还是排最前真正麻烦的不是语法,而是业务语义——NULL 到底代表“未填”“无效”还是“不适用”?同一个字段在不同场景下可能需要不同处理:有时该归进 default 组,有时该单独统计,有时该过滤掉。别指望一个 COALESCE 通吃所有情况。