在SQL查询中,聚合函数通常用于按组汇总数据,而窗口函数可以在保留原行的基础上进行计算。当我们需要先按某个维度聚合出指标,再基于该指标计算排名时,可以把聚合函数作为窗口函数使用,然后在外层套用排名函数。

基本思路
假设有一张成绩表 score,字段包括 student_id、subject、score。我们想算出每个学生的总分,并按总分从高到低排名。核心做法是:先用 SUM() OVER() 得到每个学生的总分,再用 RANK() OVER() 对总分排名。
示例表结构
| student_id | subject | score |
|---|---|---|
| 1 | 语文 | 80 |
| 1 | 数学 | 90 |
| 2 | 语文 | 85 |
| 2 | 数学 | 85 |
使用聚合窗口函数计算总分
下面的查询通过 SUM(score) OVER(PARTITION BY student_id) 计算每个学生的总分,结果不会合并行:
SELECT student_id, subject, score, SUM(score) OVER(PARTITION BY student_id) AS total_score FROM score;
结合排名窗口函数
在得到总分后,可以用 RANK() 或 DENSE_RANK() 根据总分排名。为了逻辑清晰,通常使用子查询或公用表表达式:
WITH stu_total AS (
SELECT
student_id,
SUM(score) OVER(PARTITION BY student_id) AS total_score
FROM score
)
SELECT
student_id,
total_score,
RANK() OVER(ORDER BY total_score DESC) AS rk
FROM stu_total
GROUP BY student_id, total_score
ORDER BY rk;
RANK 与 DENSE_RANK 的区别
- RANK:相同总分排名相同,后续排名会跳过,例如 1、1、3。
- DENSE_RANK:相同总分排名相同,后续排名连续,例如 1、1、2。
结合 AVG 聚合函数排名
如果按平均分排名,只需把 SUM 换成 AVG:
WITH stu_avg AS (
SELECT
student_id,
AVG(score) OVER(PARTITION BY student_id) AS avg_score
FROM score
)
SELECT
student_id,
avg_score,
DENSE_RANK() OVER(ORDER BY avg_score DESC) AS rk
FROM stu_avg
GROUP BY student_id, avg_score
ORDER BY rk;
小结
将聚合函数写成窗口形式,可以在不丢失明细行的前提下得到汇总值;再配合 RANK 等排序窗口函数,就能轻松实现基于聚合结果的排名。这种模式在报表统计和排行榜场景中非常实用。