聚合函数与 NULL 的关系
SUM、AVG、MAX、MIN 会忽略 NULL 输入,而 COUNT 家族行为不同:COUNT(*) 统计所有行,COUNT(col) 只统计该列非 NULL 的行。空集上除 COUNT 外都返回 NULL。这组规则直接决定报表数字能不能对上。
基本信息
| 忽略 NULL | SUM、AVG、MAX、MIN、COUNT(col) 都跳过 NULL |
|---|---|
| COUNT(*) | 统计所有行,包括整行列值都为 NULL 的行 |
| 空集结果 | SUM、AVG、MAX、MIN 返回 NULL;COUNT 返回 0 |
| AVG 分母 | 非 NULL 值个数,与总行数无关 |
| MIN / MAX | 忽略 NULL,但不会把 NULL 变成值 |
| 分组后 | 某个分组的值全为 NULL 时,SUM 返回 NULL |
行为演示
行为演示
CREATE TABLE t_demo (v INT);
SELECT COUNT(*), COUNT(v), SUM(v), AVG(v)
FROM t_demo; -- 0, 0, NULL, NULL:空集上的差异
INSERT INTO t_demo VALUES (1), (NULL), (3);
SELECT COUNT(*), COUNT(v), SUM(v), AVG(v)
FROM t_demo; -- 3, 2, 4, 2.0000:AVG 分母是 2 不是 3函数行为对照
| 函数 | NULL 如何处理 | 空集结果 |
|---|---|---|
| COUNT(*) | 计数,不看列值 | 0 |
| COUNT(col) | 跳过 NULL | 0 |
| SUM(col) | 跳过 NULL | NULL |
| AVG(col) | 跳过 NULL,分母为非 NULL 个数 | NULL |
| MAX / MIN | 跳过 NULL | NULL |
| GROUP_CONCAT | 跳过 NULL | NULL(没有可拼接的值) |
典型使用场景
- 报表接口取值:先确认聚合列是否可能返回 NULL
- 数据质量检查:对比 COUNT(*) 与 COUNT(col) 找出缺失值比例
- 计算填充率:COUNT(col) 除以 COUNT(*) 得到非空比例
- 分组统计:某组全为空值时单独标注,避免展示空白
- 对账:确认两侧口径是忽略 NULL 还是把 NULL 当 0
- 补数排查:找出因为 SUM 返回 NULL 而没进报表的区间
- 接口返回前统一兜底:金额类指标补 0,比率类指标保留 NULL 并单独标注
- 抽样核对:用 COUNT(*)、COUNT(col) 与 SUM 三个值交叉验证数据是否缺列
COUNT(col) 与 COUNT(*) 的差值就是缺失值数量:数据质量报表里常用 COUNT(*) 减去 COUNT(col) 表示某列的空值行数,比额外跑一次 IS NULL 查询更省。
排查与兜底写法
排查与兜底写法
-- 统计某列的空值行数:总数减去非空计数
SELECT COUNT(*) - COUNT(amount) AS null_amount_rows FROM orders;
-- 分组后兜底,避免报表出现空单元格
SELECT user_id, COALESCE(SUM(amount), 0) AS total
FROM orders
GROUP BY user_id; -- 无订单用户显示 0,而不是空白MAX 与 MIN 也忽略 NULL:如果整列都是 NULL,结果是 NULL 而不是空字符串或 0。做“最近一次时间”统计时要考虑这一层,否则展示出来的“最新时间”可能为空。
空集上 SUM 返回 NULL:接口直接把 null 暴露出去容易让前端报错,用 COALESCE 兜底成 0;同时要让业务知道“没有数据”和“合计为 0”是两回事。