AVG()配合GROUP BY可计算各分组平均值,但SELECT中非聚合字段必须出现在GROUP BY中;AVG自动忽略NULL,全NULL组返回NULL;WHERE在分组前过滤,HAVING在分组后筛选。

GROUP BY 后用 AVG() 函数直接算平均值
SQL 里算分组平均值,核心就是 AVG() 配合 GROUP BY。不能只写 AVG(column) 就完事——那会把整张表当一组,返回单个值;必须明确告诉数据库“按什么分组”,否则语法报错或结果错乱。
常见错误现象:SELECT name, AVG(score) FROM students; 在多数数据库(如 PostgreSQL、MySQL 8.0+ 严格模式)会直接报错:column "students.name" must appear in the GROUP BY clause or be used in an aggregate function。
- 正确写法:所有非聚合字段(比如
name、department)都得出现在GROUP BY子句里 - 如果字段有 NULL,
AVG()默认自动过滤掉,不影响计算(不用额外加WHERE column IS NOT NULL) - 想保留 NULL 组?可以先用
COALESCE()或CASE WHEN处理,但注意这会改变分组逻辑
处理空组或全 NULL 分组时 AVG() 返回 NULL
AVG() 在某组内所有值都是 NULL 时,结果是 NULL,不是 0。这点容易被忽略,尤其在做报表或对接前端时可能引发空值异常。
示例场景:统计每个部门的平均薪资,但某个部门暂时没员工记录,或者所有员工薪资字段为空。
- 用
COALESCE(AVG(salary), 0)把 NULL 转成 0(适合业务上“无数据=0”) - 用
COUNT(*)配合判断是否真有数据:CASE WHEN COUNT(*) = 0 THEN 'no data' ELSE CAST(AVG(salary) AS DECIMAL(10,2)) END - 注意:MySQL 的
AVG()对空组也返回 NULL;PostgreSQL 和 SQL Server 行为一致;SQLite 同样如此
不同数据库对 AVG() 类型推导的差异
算出来的平均值类型不总是一致——这会影响后续计算或导出精度。比如整数列 score INT,在 MySQL 中 AVG(score) 默认返回 DECIMAL(10,2),而 PostgreSQL 返回 numeric,SQLite 返回浮点数。
- 需要固定小数位?显式转换更可靠:
ROUND(AVG(score), 2)或CAST(AVG(score) AS DECIMAL(5,2)) - 在 JOIN 或子查询中参与运算时,类型不匹配可能触发隐式转换,导致精度丢失(比如和整数相加后截断小数)
- 如果源列是
FLOAT,某些数据库(如 older SQL Server)可能因浮点误差让AVG()结果带微小偏差,生产环境建议用DECIMAL列存金额类数据
WHERE 和 HAVING 的位置决定过滤时机
想筛掉某些行再算平均?用 WHERE;想筛掉某些分组的结果?用 HAVING。顺序错了,结果就偏了。
典型误用:SELECT dept, AVG(salary) FROM emp WHERE AVG(salary) > 5000 GROUP BY dept; —— 这会报错,因为 WHERE 执行时聚合还没发生。
- 先过滤行:用
WHERE salary > 0去掉异常负值,再分组求平均 - 后过滤组:用
HAVING AVG(salary) > 5000只保留平均薪资超 5000 的部门 -
HAVING可以引用SELECT中的别名(如SELECT dept, AVG(salary) AS avg_sal ... HAVING avg_sal > 5000),但并非所有数据库都支持(MySQL 支持,PostgreSQL 要求写完整表达式)
WHERE 和 HAVING,最后检查 NULL 和类型——这三步漏一步,结果就容易出岔子。

















