avg()必须配合group by department才能按部门计算平均值,否则返回全公司总平均数或报错;非聚合字段须全部写入group by;avg()自动忽略null但不处理空字符串等异常值;排除极值需用窗口函数或子查询;order by应使用列序号或表达式而非中文别名。

AVG() 必须配合 GROUP BY 才能按部门计算平均值
直接写 SELECT AVG(salary) FROM employees 只会返回全公司一个总平均数,不是每个部门的。要分组,GROUP BY department 是硬性前提,漏掉就会报错或结果错乱。
常见错误现象:ORA-00937: not a single-group group function(Oracle)或 MySQL 严格模式下报错“Invalid use of group function”,本质都是没加 GROUP BY 却用了聚合函数。
- 必须把所有非聚合字段(如
department)都写进GROUP BY子句 - 如果还选了
employee_name这类明细字段,一定会报错——它不属于分组维度,也不参与聚合 - MySQL 5.7+ 默认开启
ONLY_FULL_GROUP_BY,会强制校验,老版本可能“侥幸”出结果但不可靠
处理 NULL 工资值:AVG() 默认自动忽略 NULL,但得确认数据质量
AVG() 对 NULL 值天然免疫,不会把它当 0 算,这点比手写 SUM()/COUNT() 更省心。但问题常出在数据本身:比如 salary 字段存的是空字符串 '' 或字符串 'N/A',这些不是 NULL,会被 AVG() 当作非法值报错(如 ERROR 1292: Truncated incorrect DOUBLE value)。
- 先用
SELECT * FROM employees WHERE salary = '' OR salary REGEXP '^[^0-9.-]+'检查异常值 - 清洗时用
NULLIF(salary, '')把空字符串转成NULL,再套AVG() - 如果业务上 0 工资是合法的(如实习岗),就别用
COALESCE(salary, 0)强制替换,否则拉低均值
想排除极值干扰?AVG() 本身不支持,得换思路
标准 AVG() 没有内置的“去掉最高最低再算”功能。如果部门人数少(比如只有 3 人),一个 CEO 工资可能让平均值完全失真。
- MySQL 8.0+ 可用窗口函数:先
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary)排序,再外层过滤掉首尾 10% - 更通用的做法是用子查询 +
LIMIT配合OFFSET截取中间 80% 数据,但要注意不同数据库语法差异(PostgreSQL 用OFFSET/FETCH,SQL Server 用TOP) - 简单粗暴法:加
HAVING COUNT(*) > 5过滤掉样本太少的部门,避免单点异常主导结果
ORDER BY 和别名的坑:列名不能直接用中文或带空格
写 SELECT department, AVG(salary) AS 平均工资 FROM employees GROUP BY department ORDER BY 平均工资 DESC 在某些数据库(如 SQL Server)会报错,因为 ORDER BY 里用了中文别名,而解析器可能未完成别名绑定。
- 稳妥写法:用数字序号,如
ORDER BY 2 DESC(表示第二列) - 或重复表达式:
ORDER BY AVG(salary) DESC(注意不能写ORDER BY 平均工资,除非数据库明确支持别名引用) - 别名含空格或特殊字符时,必须用反引号(MySQL)或双引号(PostgreSQL/SQL Server)包裹,例如
AS `avg salary`
实际执行前,先跑一遍 SELECT department, COUNT(*), AVG(salary) FROM employees GROUP BY department 看看各组记录数和均值量级是否合理——部门人数为 0 的不会出现在结果里,但人数为 1 且工资异常高,就得人工核对。










