MySQL的窗口函数(Window Functions)
一、窗口函数核心概念
-  窗口(Window) 
 窗口是数据行的集合,由OVER()子句定义。它决定了函数计算的“数据范围”,可以是一个分区的全部行、当前行前后的行,或动态变化的子集。
-  语法结构 SELECT window_function(column) OVER ([PARTITION BY partition_expression][ORDER BY order_expression [ASC|DESC]][frame_clause]) AS alias FROM table;- PARTITION BY:将数据划分为多个分区(类似GROUP BY),函数在每个分区内独立计算。
- ORDER BY:定义分区内数据的排序方式,影响窗口函数的计算顺序。
- frame_clause:定义窗口的具体范围(如当前行及其前后N行)。
 
- PARTITION BY:将数据划分为多个分区(类似
二、窗口函数分类及示例
1. 聚合类窗口函数
普通聚合函数(如SUM、AVG、COUNT)结合OVER()使用,实现累计、移动平均等效果。
示例:计算累计销售额
SELECT order_date,amount,SUM(amount) OVER (ORDER BY order_date) AS cumulative_sum
FROM sales;结果:
order_date | amount | cumulative_sum
-------------------------------------
2023-01-01 | 100    | 100
2023-01-02 | 200    | 300
2023-01-03 | 150    | 4502. 排名类窗口函数
- ROW_NUMBER():为每行分配唯一序号(相同值也会不同)。
- RANK():相同值的行排名相同,后续序号跳跃(如1,1,3)。
- DENSE_RANK():相同值的行排名相同,后续序号连续(如1,1,2)。
示例:按销售额排名
SELECT product,sales,ROW_NUMBER() OVER (ORDER BY sales DESC) AS row_num,RANK() OVER (ORDER BY sales DESC) AS rank,DENSE_RANK() OVER (ORDER BY sales DESC) AS dense_rank
FROM products;结果:
product | sales | row_num | rank | dense_rank
--------------------------------------------
A       | 500   | 1       | 1    | 1
B       | 500   | 2       | 1    | 1
C       | 400   | 3       | 3    | 23. 分布类窗口函数
- PERCENT_RANK():计算行的相对排名百分比(范围[0,1])。
- CUME_DIST():计算行的累积分布(当前行及其之前行的占比)。
示例:计算销售额分布
SELECT product,sales,PERCENT_RANK() OVER (ORDER BY sales) AS percent_rank,CUME_DIST() OVER (ORDER BY sales) AS cume_dist
FROM products;4. 前后函数
- LAG(column, N):获取当前行前N行的值。
- LEAD(column, N):获取当前行后N行的值。
示例:计算销售额环比增长
SELECT month,sales,LAG(sales, 1) OVER (ORDER BY month) AS prev_sales,(sales - LAG(sales, 1) OVER (ORDER BY month)) / LAG(sales, 1) OVER (ORDER BY month) AS growth_rate
FROM monthly_sales;结果:
month | sales | prev_sales | growth_rate
----------------------------------------
Jan   | 1000  | NULL       | NULL
Feb   | 1200  | 1000       | 0.2
Mar   | 1500  | 1200       | 0.25三、窗口帧(Frame Clause)
通过ROWS或RANGE定义窗口的具体范围:
- ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:从分区开始到当前行。
- ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING:当前行的前一行到后一行。
示例:计算3个月移动平均
SELECT month,sales,AVG(sales) OVER (ORDER BY monthROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg
FROM monthly_sales;结果:
month | sales | moving_avg
---------------------------
Jan   | 100   | 100.0
Feb   | 200   | 150.0
Mar   | 150   | 150.0
Apr   | 300   | 216.7四、使用场景
- 排名与分组排名:按部门、时间等分区后排序。
- 累计计算:累计销售额、年累计增长率。
- 移动统计:移动平均、移动求和。
- 数据对比:当前行与前一行的差值或比率。
五、注意事项
- MySQL版本:窗口函数需MySQL 8.0+,旧版本不支持。
- 性能优化:合理使用索引和分区,避免全表扫描。
- 执行顺序:窗口函数在WHERE、GROUP BY、HAVING之后执行。
