在数据处理中,我们常常需要按某一列分组求出平均值,同时又不希望丢失原来的每一行记录。传统GROUP BY会把组内多行压缩成一行,导致原始明细消失。借助SQL的OVER子句,我们可以在保留原行的前提下完成分组平均计算。

为什么GROUP BY不能满足需求
当我们执行如下语句时,结果只会留下每个组一行:
SELECT dept_id, AVG(salary) AS avg_salary FROM employee GROUP BY dept_id;
这样看不到某个员工原来的工资,也无法把组平均值和具体员工记录放在同一行比较。
OVER子句的基本用法
OVER子句定义在窗口函数上,PARTITION BY指定分组字段,它不会合并行,而是为每一行计算所在组的聚合值。
SELECT emp_id, dept_id, salary, AVG(salary) OVER (PARTITION BY dept_id) AS dept_avg_salary FROM employee;
上面语句中,每一行都多出一列dept_avg_salary,表示该员工所在部门的平均工资,原行完全保留。
带排序和别名的完整示例
以下示例在MySQL、PostgreSQL等常见库中均可运行:
-- 建表并插入示例数据 CREATE TABLE employee ( emp_id INT, dept_id INT, salary INT ); INSERT INTO employee VALUES (1, 10, 5000), (2, 10, 7000), (3, 20, 4000), (4, 20, 6000); -- 查询每个员工及所在部门平均薪资 SELECT emp_id, dept_id, salary, AVG(salary) OVER (PARTITION BY dept_id) AS dept_avg FROM employee ORDER BY dept_id, emp_id;
注意事项
- OVER子句里的PARTITION BY类似于GROUP BY的分组逻辑,但不做行压缩。
- 如果还要按组内排序可用ORDER BY放在OVER内部,例如
OVER(PARTITION BY dept_id ORDER BY salary)会计算累计平均。 - 窗口函数不能直接写在WHERE中,需要包一层子查询或CTE来过滤。
小结
使用OVER子句加PARTITION BY,是用SQL统计每组平均值同时显示原行的最直接方式。它既给出了分组聚合结果,又保住了业务明细,在报表查询和数据分析里非常实用。