NULL是缺失标记而非值,WHERE中必须用IS NULL而非= NULL;GROUP BY将NULL视为相等并归为一组;JOIN时NULL无法匹配,需用LEFT JOIN配合COALESCE处理。

WHERE 子句中 IS NULL 和 = NULL 的区别必须分清
SQL 里 NULL 不是值,而是“缺失”的标记,所以不能用等号判断。写 WHERE column = NULL 永远不返回任何行,因为 NULL = NULL 返回 UNKNOWN,而 WHERE 只接受 TRUE。
正确写法只有:WHERE column IS NULL 或 WHERE column IS NOT NULL。
- 某些方言(如 PostgreSQL)支持
IS DISTINCT FROM,能安全比较含NULL的字段,但 MySQL、SQL Server 不支持 -
COALESCE(column, 'default')常用来临时替换NULL,但注意它会改变原始数据语义,做统计前要确认是否合理 -
聚合函数如
COUNT(column)自动忽略NULL,但COUNT(*)统计所有行——这点常被误用
GROUP BY 中遇到 NULL 会被当成同一组吗?
是的。在标准 SQL 中,所有 NULL 在 GROUP BY 中被视为相等,会归入同一组。比如 SELECT region, COUNT(*) FROM sales GROUP BY region,所有 region IS NULL 的记录会挤在一行里,显示为 NULL。
如果想把缺失值单独标记(比如叫 'Unknown'),得提前转换:
SELECT COALESCE(region, 'Unknown') AS region_group, COUNT(*) FROM sales GROUP BY COALESCE(region, 'Unknown');
- 别在
GROUP BY里直接写COALESCE(region, 'Unknown')而不重命名,否则 SELECT 列名和 GROUP BY 表达式不一致,在严格模式(如 PostgreSQL)下报错 - MySQL 5.7+ 默认开启
ONLY_FULL_GROUP_BY,要求 SELECT 中所有非聚合列必须出现在 GROUP BY 中,这时候裸写region会失败
窗口函数里 NULL 怎么影响排序和计算?
ORDER BY 在窗口函数中决定计算顺序,而 NULL 的排序行为因数据库而异:PostgreSQL 默认 NULLS LAST,MySQL 8.0 默认 NULLS FIRST(实际取决于版本和 SQL mode)。这会导致 ROW_NUMBER()、LAG() 等结果不一致。
显式声明更安全:
SELECT id, value,
LAG(value) OVER (ORDER BY created_at NULLS LAST) AS prev_value
FROM logs;
-
LAG(value, 1, 0)的第三个参数是默认值,当上一行是NULL或越界时返回0,避免结果列出现意外NULL -
AVG()窗口函数仍会跳过NULL,但如果你先用ROWS BETWEEN 2 PRECEDING AND CURRENT ROW定义帧,空值不会被“补上”,只是参与计数但不参与求和——容易误判平均值分母
JOIN 时 NULL 匹配逻辑容易引发漏数据
两个表 ON 条件里如果涉及可能为 NULL 的字段(比如 ON a.category_id = b.id),而 a.category_id 是 NULL,那这行一定不会匹配成功——因为 NULL = anything 永远不成立。
若业务上希望把“未知分类”的记录也连过去(比如挂到 b.id IS NULL 的虚拟行),得拆成两步或改用条件逻辑:
- 用
LEFT JOIN保证左表全量,再在 WHERE 或 SELECT 中用COALESCE(b.name, 'Uncategorized')标记 - 避免写
ON a.category_id = b.id OR a.category_id IS NULL——这会引发笛卡尔积,性能爆炸 - 部分场景更适合用
UNION ALL分开处理:先正常 JOIN,再补上a.category_id IS NULL的行并关联默认值
缺失值不是技术边缘问题,它是分析链路里最常被静默吞掉的信息源。每加一层聚合、一次 JOIN、一个窗口定义,都得重新检查 NULL 是否还在按你设想的方式参与计算。










