Mxsleon Blog

Back

窗口函数(window function)是mysql8.0 以后才引用的新函数,用于计算累加、排名、序号类的问题。
最经典的就是row_number() 函数,用于既定规则的排序。

什么是窗口函数

窗口函数的本质:
- 即想聚合计算,又不想丢失原始行
在窗口函数中:
- 保留每一行
- 还能看到:
- 排名
- 累加
- 平均值
- 前一行
- 后一行
- 当前行附近的数据

这就是:
在一组行上进行计算,但又不折叠行

可以和分组函数进行区别 Group by

题目解析

在力扣 1204. 最后一个能进入巴士的人
题目中,使用turn进行排序,标记进入巴士的顺序,并且标定了最大限重1000KG ,这是典型的累加窗口函数的使用场景,因此,题解sql为:

with a as( 
select person_name, weight, turn, 
sum(weight) over(order by turn) sum_weight 
from queue 
) 

select person_name 
from a 
where sum_weight <= 1000 
order by turn desc 
limit 1

数据(简化数据 Queue 表按 turn 列由小到大排序。)

Turn ID Name Weight Total Weight
1 5 Alice 250 250
2 3 Alex 350 600
3 6 John Cena 400 1000 最后一个上巴士
4 2 Marie 200 1200 无法上巴士
5 4 Bob 175 ___
6 1 Winston 500 ___

sql执行顺序

其中,with表达式中,对数据进行了累加求和:

sum(weight) over(order by turn)

排序列,turn:对turn升序排序
窗口以Turn计数

  • 第一行:
    窗口:
    【1】
    计算:
    250

  • 第二行:
    窗口:
    【1,2】
    计算:
    250 + 350 = 600

  • 第三行
    窗口:
    【1,2,3】
    计算:
    250 + 350 + 400 = 1000

并最终,按照sum(weight) over(order by turn) sum_weight 语法:

person_name weight turn sum_weight
Alice 250 1 250
Alex 350 2 600
John Cena 400 3 1000
Marie 200 4 1200
Bob 175 5 1375
Winston 500 6 1875

实现数据的累加。

理解窗口函数中的窗口

直接从语法讲解,窗口函数仿佛晦涩一些,我之前都是死记硬背语法,聚合函数后接over(),然后接PARTITION BY分区啊巴拉巴拉的。
难以理解,不用就会忘掉,实际没有理解窗口函数的精髓。

一言以蔽之,窗口函数,解决的问题在于,让当前行,可以看到其他行。
理解了数据库当前到底在观察那一批数据,就可以明白窗口函数的用法以及概念。

函数的典型结构为:

SELECT
    [窗口函数] OVER (
        [PARTITION BY 分区字段]
        [ORDER BY 排序字段]
        [窗口帧定义]
    ) AS 列名
FROM 表;

我们来逐步拆解:

OVER 作用

作用:定义当前行的观察范围

可以理解为:当前行能看到谁?
例如:SUM(salary) OVER ()
意思为:当前行可以看到全表

例如,表:

name salary
张三 3000
李四 5000
王五 7000

sql:
SELECT name, salary, SUM(salary) OVER () FROM emp;

结果:

name salary sum
张三 3000 15000
李四 5000 15000
王五 7000 15000

其中,sum的结果每一行都是 15000 因为,当前的每一行都能看到全表

PARTITION BY 作用

partition 的本质:把大窗口切成小窗口
可以理解为:分组观察
效果类似与分组GROUP BY ,但是结果被压缩,指示分组观察。

例如,表:

name dept salary
张三 技术 3000
李四 技术 5000
王五 财务 7000

sql:

SELECT
    name,
    dept,
    salary,
    SUM(salary) OVER (
        PARTITION BY dept
    ) AS dept_sum
FROM emp;

数据库的执行:
对于 张三 PARTITION BY dept
意味着:张三只能看到“技术部”
那么在 张三 数据行 ,张三 能OVER观察到:
【张三,李四】
所以,SUM
3000 + 5000 = 8000

对于 王五 ,只能OVER观察到 财务部
所以dept_sum数据为7000

最终结果:

name dept salary dept_sum
张三 技术 3000 8000
李四 技术 5000 8000
王五 财务 7000 7000

注意,PARTITION BY 不是 GROUP BY
虽然都是分组,但PARTITION BY 是划分观察范围;GROUP BY会折叠压缩行

ORDER BY 作用

这是窗口内部的顺序
这对于窗口函数非常重要,定义了排序的规则、累加的反向等。

例如:

SUM(salary) OVER (
    ORDER BY id
)

意为当前行按照 id 顺序逐步观察

为什么ORDER BY 能实现累计?

直接上例子,表:

id salary
1 100
2 200
3 300

sql:
SUM(salary) OVER ( ORDER BY id )

  • 对于第一行
    窗口:100
    SUM:100
  • 第二行
    窗口:100 200
    SUM:300
  • 第三行
    窗口:100 200 300
    SUM:600

于是结果:

id salary sum
1 100 100
2 200 300
3 300 600

为什么会越来越多?实现了累加?
因为:ORDER BY 默认生成:从第一行 到 当前行
这就是窗口帧 窗口帧(Window Frame)

窗口帧

汇总来看整个窗口函数:
PARTITION BY:决定能看到那些人;
ORDER BY:决定按什么顺序看;
窗口帧:决定具体看到第几行.

更加形象的例子在于:
- PARTITION BY = 班级
- ORDER BY = 学号排序
- 窗口帧 = 你视线能看到前后几个人

以上就是我自己对于窗口函数的理解,比较浅显,如有错误或者理解偏差,欢迎指正

Mysql窗口函数
https://blog.mxsleon.com/blog/mysql_window_function/blog/mysql_window_function
Author mxsleon
Published at May 21, 2026