直接用MAX()和AVG()窗口函数可计算部门内最高工资与平均工资差额,但需确保PARTITION BY子句完全一致;混用GROUP BY与OVER()会导致语义错误或报错;整数类型salary需显式转DECIMAL或乘1.0避免AVG精度丢失。

用 OVER() 计算部门内最高工资与平均工资的差额
直接用 MAX(salary) OVER (PARTITION BY dept) 和 AVG(salary) OVER (PARTITION BY dept) 就能算出差额,不需要子查询或自连接。关键在于两个窗口函数必须用完全相同的 PARTITION BY 子句,否则结果会错位。
为什么不能混用 GROUP BY 和 OVER()
如果在同一个查询里写 GROUP BY dept,再加 OVER(PARTITION BY dept),多数数据库(如 PostgreSQL、SQL Server)会报错;MySQL 8.0+ 虽允许,但语义混乱——OVER 在分组后计算,而分组已把多行压成一行,AVG 和 MAX 变成单值,差额恒为 0。
-
GROUP BY是聚合操作,输出每部门一行 -
OVER()是窗口操作,保持原始行数,给每行附带聚合结果 - 要保留员工明细并显示“本部门最高工资减平均工资”,必须只用
OVER,不用GROUP BY
AVG() 的精度陷阱:整数除法导致结果为 0
很多表的 salary 是 INT 类型,AVG(salary) 在某些数据库(如 PostgreSQL)中仍返回整数,造成截断。例如部门工资是 [5000, 6000, 7000],AVG 算出来可能变成 6000 而非 6000.0,和 MAX=7000 相减得 1000,看似对,但若工资是 [5000, 5500],整数 AVG 就是 5000(不是 5250),差额失真。
- 显式转类型:
AVG(CAST(salary AS DECIMAL(10,2))) OVER (PARTITION BY dept) - 或乘 1.0 强制提升:
AVG(salary * 1.0) OVER (PARTITION BY dept) - MySQL 中
AVG()默认返回DOUBLE,但为跨库兼容,仍建议加CAST
完整可跑示例(PostgreSQL / MySQL 8.0+ / SQL Server)
SELECT
name,
dept,
salary,
MAX(salary) OVER (PARTITION BY dept) AS dept_max_salary,
AVG(CAST(salary AS DECIMAL(10,2))) OVER (PARTITION BY dept) AS dept_avg_salary,
ROUND(
MAX(salary) OVER (PARTITION BY dept) -
AVG(CAST(salary AS DECIMAL(10,2))) OVER (PARTITION BY dept),
2
) AS diff_from_dept_avg
FROM employees;
注意:别名不能在同行表达式里复用(比如不能写 dept_max_salary - dept_avg_salary),因为列别名在 SELECT 子句中不可见;必须重复写窗口函数,或用外层 SELECT * 包裹。
真正容易被忽略的是:差额字段本身没有业务含义,它只是部门内部相对位置的度量——高差额不等于高薪,只说明该员工离本部门均值较远;如果要做跨部门比较,得先标准化(比如用 Z-score),OVER 本身不解决这个问题。










