AVG()配合GROUP BY是计算分组平均值的唯一正确方式;它自动忽略每组内的NULL值,全NULL组返回NULL,非聚合字段须全部出现在GROUP BY中,WHERE用于分组前过滤,HAVING用于分组后过滤。

GROUP BY 后直接用 AVG() 就行,但得注意 NULL 和空组
SQL 里算分组平均值最常用的就是 AVG() 配合 GROUP BY,它会自动跳过该组内的 NULL 值——这点容易被忽略,比如你有一组数据:score 列包含 85, NULL, 92, 78,AVG(score) 结果是 (85 + 92 + 78) / 3 = 85,不是除以 4。
如果某组所有值都是 NULL,AVG() 返回 NULL,不会报错,但后续逻辑可能出问题(比如和 0 比较或参与加法)。
- 确保分组字段不为
NULL才能形成有效组(NULL会单独成一组,常被误认为“没数据”) - 想排除
NULL且同时过滤掉整组无效记录,加HAVING COUNT(score) > 0 - 需要把
NULL当 0 处理?先用COALESCE(score, 0)再套AVG(),但语义已变(变成“含缺考按零分计”的平均)
WHERE 和 HAVING 的位置不能颠倒
WHERE 过滤的是原始行,HAVING 过滤的是分组后的聚合结果。想算“每个班级中及格学生的平均分”,必须先用 WHERE score >= 60 筛出行,再 GROUP BY class;如果写成 HAVING AVG(score) >= 60,得到的是“平均分不低于 60 的班级”的平均分——完全不同的业务含义。
-
WHERE中不能用AVG()、COUNT()等聚合函数 -
HAVING必须跟在GROUP BY后面,没GROUP BY却写HAVING会报错(MySQL 5.7+ 默认严格模式下) - 性能上,
WHERE越早过滤掉无关行,GROUP BY处理的数据越少
不同数据库对空组的处理差异要留意
标准 SQL 规定:如果 GROUP BY 字段全为 NULL,应归为一组。但 PostgreSQL 和 SQL Server 严格遵守,MySQL(尤其是旧版本)有时表现不一致——比如 GROUP BY category,当 category 全是 NULL,MySQL 可能返回空结果集而非一行 NULL 平均值。
- 测试时用明确含
NULL的小数据集验证,别只靠文档 - 跨库迁移时,若依赖
NULL分组行为,建议显式写成GROUP BY COALESCE(category, '_null_')避免歧义 - SQLite 对
AVG()返回类型较宽松(可能返回整数),需要小数精度时显式乘1.0或用CAST(AVG(x) AS REAL)
需要带小数位数控制?别只靠 ROUND()
ROUND(AVG(score), 2) 看似合理,但要注意:它只是四舍五入显示值,内部计算仍用原始精度。更麻烦的是,有些场景(如财务统计)要求“汇总前每组平均值截断到小数点后两位”,这时 ROUND() 放在 AVG() 外层就不对了——应该先 ROUND(score, 2) 再 AVG(),否则误差会累积。
- PostgreSQL 支持
AVG(score)::DECIMAL(5,2)直接定义精度 - MySQL 用
FORMAT(AVG(score), 2)是转字符串,不能参与后续数值计算 - 真正要控制中间精度,得用子查询或 CTE 先处理原始值
NULL、分组键是否稳定、目标库对空值和精度怎么处理,比死记语法重要得多。

















