SUM和AVG自动忽略NULL值,分母为非NULL行数;NULL需用COALESCE转0才参与计算;聚合后过滤须用HAVING而非WHERE;不可直接嵌套聚合函数,需子查询或窗口函数实现。

直接用 SUM 和 AVG 就能算,但 NULL 会自动被忽略
这两个函数默认跳过 NULL 值,不是报错也不是当成 0。比如某列有 10, 20, NULL, 30,SUM 返回 60,AVG 返回 20(即 60 / 3),分母是非 NULL 行数,不是总行数。
- 如果想把
NULL当成 0 参与计算,得先用COALESCE(col, 0)或IFNULL(col, 0)(MySQL)转换 -
AVG对空结果集返回NULL,不是 0 —— 这点容易在聚合后做判断时出错 - 整数列用
AVG可能截断小数:PostgreSQL 和 SQL Server 默认保留小数位,但 SQLite 和旧版 MySQL 可能返回整数,建议显式转成DECIMAL或加.0(如AVG(col * 1.0))
按组求和/平均值必须配 GROUP BY,漏写会报错或结果错乱
只要 SELECT 里有聚合函数,又同时选了普通列(比如 SELECT dept, SUM(salary)),就必须写 GROUP BY dept。否则多数数据库(如 PostgreSQL、SQL Server)直接报错;MySQL 在严格模式下也报错,非严格模式可能返回不确定的任意一行值,极易误导。
-
GROUP BY的字段必须和 SELECT 中的非聚合列完全一致(不能是别名,除非方言支持,如 PostgreSQL 9.6+) - 想对多个维度分组,比如“部门 + 年份”,就写
GROUP BY dept, YEAR(hire_date) - 聚合后过滤不能用
WHERE,得用HAVING——例如只看平均工资超 8000 的部门:HAVING AVG(salary) > 8000
SUM 和 AVG 不能直接嵌套其他聚合,常见误写是 AVG(SUM(x))
这种写法语法错误。聚合函数不能直接嵌套,因为 SUM 输出的是单个标量,而 AVG 需要一组值。真要算“各组 SUM 的平均值”,得用子查询或 CTE:
SELECT AVG(total_per_dept) FROM ( SELECT SUM(sales) AS total_per_dept FROM orders GROUP BY region ) t;
- 窗口函数可以绕过嵌套限制,比如
AVG(SUM(sales)) OVER ()是合法的(先按 PARTITION 分组求 SUM,再在整个结果上算 AVG) - 误用
AVG(DISTINCT col)想去重求均值?注意它算的是去重后所有值的平均,不是每组去重再平均 - 某些场景下,
SUM比COUNT更适合统计“有效记录数”:比如用SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END)替代条件计数
性能提示:没索引的数值列上跑 AVG 可能全表扫描,尤其大表
SUM 和 AVG 都需要遍历所有参与计算的行,无法跳过。如果只查某条件下的平均值,确保 WHERE 条件字段有索引,否则即使目标列有索引也没用。
- 复合索引要注意顺序:对于
SELECT AVG(score) FROM exam WHERE subject = 'math' AND year = 2023,索引应建为(subject, year, score),把过滤字段放前面,聚合字段放最后 - 近似计算需求(如报表预估)可考虑采样:PostgreSQL 支持
TABLESAMPLE,MySQL 8.0+ 可用SELECT AVG(score) FROM exam TABLESAMPLE SYSTEM(10)快速估算 - 频繁查某列平均值且数据变动不频繁,可建物化视图(PostgreSQL)或汇总表,避免每次实时计算
聚合函数看着简单,但 NULL 处理、分组逻辑、嵌套限制和性能边界这几个点,实际写错的概率远高于初学者预期。

















