SQL中的窗口函数通过OVER子句定义计算的数据范围,其中PARTITION BY负责将数据按照指定字段分组,ORDER BY则决定每个分组内的数据排序规则,排序方向分为升序ASC和降序DESC两种,不同的排序方向会让窗口函数的计算结果出现明显差异。

排序方向对排名类窗口函数的影响
排名类窗口函数如ROW_NUMBER、RANK、DENSE_RANK的结果和排序方向直接相关,排序方向决定了数据的排名顺序。我们先准备测试数据,创建一张学生成绩表并插入测试数据:
-- 创建学生成绩表
CREATE TABLE student_score (
student_id INT,
subject VARCHAR(20),
score INT
);
-- 插入测试数据
INSERT INTO student_score VALUES
(1, '数学', 85),
(2, '数学', 92),
(3, '数学', 85),
(4, '数学', 78),
(1, '语文', 90),
(2, '语文', 88),
(3, '语文', 95),
(4, '语文', 82);
接下来分别使用升序和降序排序,查看数学科目的排名结果:
-- 升序排序,分数从低到高排名
SELECT
student_id,
score,
ROW_NUMBER() OVER (PARTITION BY subject ORDER BY score ASC) AS asc_rank,
RANK() OVER (PARTITION BY subject ORDER BY score ASC) AS asc_rank_val,
DENSE_RANK() OVER (PARTITION BY subject ORDER BY score ASC) AS asc_dense_rank
FROM student_score
WHERE subject = '数学';
-- 降序排序,分数从高到低排名
SELECT
student_id,
score,
ROW_NUMBER() OVER (PARTITION BY subject ORDER BY score DESC) AS desc_rank,
RANK() OVER (PARTITION BY subject ORDER BY score DESC) AS desc_rank_val,
DENSE_RANK() OVER (PARTITION BY subject ORDER BY score DESC) AS desc_dense_rank
FROM student_score
WHERE subject = '数学';
升序排序时,分数最低的学生排名为1,相同分数的学生排名会按照默认规则处理;降序排序时,分数最高的学生排名为1,相同分数的处理逻辑和升序一致,只是排名的参照标准相反。
排序方向对聚合类窗口函数的影响
聚合类窗口函数如SUM、AVG、COUNT结合ORDER BY时,默认计算从分组第一行到当前行的累计值,排序方向会改变累计的计算范围。我们以学生成绩表为例,计算数学科目分数的累计总和:
-- 升序排序累计总和,从最低分开始累计
SELECT
student_id,
score,
SUM(score) OVER (PARTITION BY subject ORDER BY score ASC) AS asc_cumulative_sum
FROM student_score
WHERE subject = '数学';
-- 降序排序累计总和,从最高分开始累计
SELECT
student_id,
score,
SUM(score) OVER (PARTITION BY subject ORDER BY score DESC) AS desc_cumulative_sum
FROM student_score
WHERE subject = '数学';
升序排序时,累计总和是按照分数从低到高的顺序逐步累加;降序排序时,累计总和是按照分数从高到低的顺序逐步累加,最终的总累计值是相同的,但每个行的累计结果不同。
排序方向对取值类窗口函数的影响
取值类窗口函数如LAG、LEAD、FIRST_VALUE、LAST_VALUE的结果也会受排序方向影响,排序方向决定了相邻行或者首尾行的取值。我们查看数学科目每个学生的前一名和后一名学生的分数:
-- 升序排序时的前后行取值
SELECT
student_id,
score,
LAG(score, 1) OVER (PARTITION BY subject ORDER BY score ASC) AS prev_score_asc,
LEAD(score, 1) OVER (PARTITION BY subject ORDER BY score ASC) AS next_score_asc
FROM student_score
WHERE subject = '数学';
-- 降序排序时的前后行取值
SELECT
student_id,
score,
LAG(score, 1) OVER (PARTITION BY subject ORDER BY score DESC) AS prev_score_desc,
LEAD(score, 1) OVER (PARTITION BY subject ORDER BY score DESC) AS next_score_desc
FROM student_score
WHERE subject = '数学';
升序排序时,LAG取的是分数更低的前一名学生分数,LEAD取的是分数更高的后一名学生分数;降序排序时,LAG取的是分数更高的前一名学生分数,LEAD取的是分数更低的后一名学生分数。
使用注意事项
- 如果不指定排序方向,默认是ASC升序,实际使用时需要根据业务需求明确指定方向,避免默认规则不符合预期。
- 当ORDER BY的排序字段存在相同值时,不同窗口函数的处理逻辑不同,建议结合具体函数的特性测试排序方向的影响。
- 如果不需要排序,不要随意添加ORDER BY子句,因为聚合类窗口函数加上ORDER BY后会变成累计计算,和没有ORDER BY的结果完全不同。
SQLOVER子句PARTITION_BYORDER_BY窗口函数修改时间:2026-06-19 21:15:33