avg()必须配合group by才能按部门分组计算平均值;直接select avg(salary) from emp只返回全表均值,且自动忽略null,但某部门全为null时结果为null而非0。

AVG函数的基本用法和常见错误
AVG() 是聚合函数,必须配合 GROUP BY 才能按部门分组计算平均值;直接写 SELECT AVG(salary) FROM emp 只会返回全表平均工资,不是每个部门的。另外,AVG() 会自动忽略 NULL 值,但如果某部门所有员工薪资都是 NULL,结果就是 NULL,不是 0。
常见错误包括:忘记 GROUP BY dept_id、在 SELECT 中漏写部门字段、对非数值字段(比如 dept_name)误用 AVG() 导致报错 ERROR 1140: In aggregated query without GROUP BY。
- 确保
salary列是数值类型(如DECIMAL或INT),否则会报类型不匹配错误 - 若需显示部门名称,要确认
dept表与emp表已关联,不能只查emp表却选dept_name - 避免在
WHERE子句中过滤掉整组数据(例如WHERE salary > 5000会剔除低薪员工,但不影响分组逻辑)
带JOIN的部门平均工资查询写法
实际业务中,部门名通常存在单独的 dept 表,需要用 JOIN 关联。标准写法是:
SELECT d.dept_name, AVG(e.salary) AS avg_salary FROM emp e JOIN dept d ON e.dept_id = d.id GROUP BY d.id, d.dept_name;
注意:必须把 d.id 和 d.dept_name 都放进 GROUP BY(MySQL 5.7+ 严格模式下,只写 d.dept_name 会报错 ERROR 1055)。
- 如果
dept表里有部门没员工,用LEFT JOIN并配合COALESCE(AVG(e.salary), 0)可显示 0 -
AVG()结果默认保留小数,如需四舍五入到两位,可套ROUND(AVG(e.salary), 2) - 别名
avg_salary要加引号才能在 ORDER BY 中引用,或直接写表达式:ORDER BY AVG(e.salary) DESC
处理空值和异常数据的实用技巧
真实数据常含 0 或负数工资(可能是占位符或录入错误),AVG() 不会过滤它们,会导致结果失真。例如,某部门 3 人薪资为 8000, 9000, 0,AVG() 算出来是 5666.67,而非有效员工的均值。
- 用
WHERE salary > 0排除明显异常值(放在JOIN后、GROUP BY前) - 想保留部门结构但排除无效记录,可在
AVG()内部用条件表达式:AVG(CASE WHEN salary > 0 THEN salary END),此时该部门若无有效薪资,结果为NULL - 检查是否有重复员工记录(同一
emp_id多条薪资记录),会导致AVG()被拉高,建议先去重或核对业务逻辑
性能和索引注意事项
当员工表数据量超过十万行,AVG() + GROUP BY 查询可能变慢,尤其没索引时。关键点不在 AVG() 本身,而在分组扫描成本。
- 确保
dept_id字段上有索引(INDEX(dept_id)),否则GROUP BY会触发全表排序 - 如果只查某几个部门,务必加
WHERE dept_id IN (1,2,3),避免扫描无关分组 - 避免在
SELECT中混用聚合和非聚合字段却不GROUP BY,MySQL 8.0 默认拒绝,老版本可能返回不可靠结果
部门平均工资看着简单,但一牵扯到数据质量、关联逻辑和执行效率,就容易卡在细节上——特别是那个被忽略的 GROUP BY 字段顺序,和 JOIN 类型选错导致部门丢失,这两处最常返工。











