SQL 如何处理分析中的缺失值?

11次阅读

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

SQL 如何处理分析中的缺失值?

WHERE 子句中 IS NULL= NULL区别必须分清

sqlNULL 不是值,而是“缺失”的标记,所以不能用等号判断。写 WHERE column = NULL 永远不返回任何行,因为 NULL = NULL 返回 UNKNOWN,而 WHERE 只接受 TRUE

正确写法只有:WHERE column IS NULLWHERE column IS NOT NULL

  • 某些方言(如 postgresql)支持 IS DISTINCT FROM,能安全比较含 NULL 的字段,但 mysql、SQL Server 不支持
  • COALESCE(column, 'default') 常用来临时替换 NULL,但注意它会改变原始数据语义,做统计前要确认是否合理
  • 聚合函数count(column) 自动忽略 NULL,但 COUNT(*) 统计所有行——这点常被误用

GROUP BY 中遇到 NULL 会被当成同一组吗?

是的。在标准 SQL 中,所有 NULLGROUP 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_idNULL,那这行一定不会匹配成功——因为 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 是否还在按你设想的方式参与计算。

text=ZqhQzanResources