mysql窗口函数详解

. 窗口函数概述

窗口函数(Window Functions)用于在 不分组 的情况下对查询结果中的数据进行计算。不同于 GROUP BY,窗口函数不会对结果进行聚合,而是对 每一行 数据进行计算,并且可以基于某个 窗口(window) 定义计算范围。

语法结构

窗口函数() OVER (
    [PARTITION BY 分区列]
    [ORDER BY 排序列]
    [ROWS | RANGE 选项]
)
  • PARTITION BY:对数据进行分区,类似 GROUP BY,但不会影响行的显示。
  • ORDER BY:定义窗口内的计算顺序。
  • ROWS | RANGE:定义窗口的范围(可选)。

2. 常见窗口函数分类

2.1 排名类

用于对数据进行排名:

  • RANK():排名,相同值会获得相同排名,排名不连续。
  • DENSE_RANK():密集排名,相同值排名相同,排名连续。
  • ROW_NUMBER():行号,数据按顺序编号,且不会出现重复。

示例

SELECT id, name, score,
       RANK() OVER (ORDER BY score DESC) AS rank_num,
       DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank_num,
       ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num
FROM students;

2.2 运行总计类

计算某些列的累计值:

  • SUM() OVER ():累计求和
  • AVG() OVER ():累计平均值
  • COUNT() OVER ():累计计数
  • MAX() OVER () / MIN() OVER ():最大/最小值

示例

SELECT id, name, salary,
       SUM(salary) OVER (PARTITION BY department ORDER BY id) AS running_total
FROM employees;

2.3 偏移类

用于访问当前行的前一行、后一行或某个固定偏移的行:

  • LAG(column, offset, default) OVER ():取前 offset 行数据,默认为 NULL
  • LEAD(column, offset, default) OVER ():取后 offset 行数据,默认为 NULL
  • FIRST_VALUE(column) OVER ():取窗口内的第一行值。
  • LAST_VALUE(column) OVER ():取窗口内的最后一行值。
  • NTH_VALUE(column, N) OVER ():取窗口内的第 N 行值。

示例

SELECT id, name, salary,
       LAG(salary, 1, 0) OVER (ORDER BY id) AS prev_salary,
       LEAD(salary, 1, 0) OVER (ORDER BY id) AS next_salary
FROM employees;

3. 窗口的范围(ROWS 和 RANGE)

默认情况下,窗口函数的计算范围是 整个分区(如果有 PARTITION BY)。但 ROWSRANGE 选项可以进一步细化窗口的范围。

3.1 ROWS

ROWS 直接指定 行数 进行计算。

  • ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    • 从窗口开头到当前行的累积值(默认)。
  • ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
    • 当前行及前后 1 行的范围。
  • ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
    • 整个分区范围(等价于 SUM() OVER (PARTITION BY xxx))。

示例

SELECT id, name, salary,
       SUM(salary) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS rolling_sum
FROM employees;

计算当前行及前 2 行的累积工资总和。

3.2 RANGE

RANGE数值范围 计算,通常与 ORDER BY 一起使用。

  • RANGE BETWEEN INTERVAL 3 DAY PRECEDING AND CURRENT ROW
    • 计算当前行及前 3 天的数据(适用于日期字段)。

示例

SELECT id, name, order_date, amount,
       SUM(amount) OVER (ORDER BY order_date RANGE BETWEEN INTERVAL 3 DAY PRECEDING AND CURRENT ROW) AS sum_last_3_days
FROM orders;

计算过去 3 天的订单金额总和。


4. 窗口函数 vs 聚合函数

函数类型 作用 示例 计算范围
SUM() 聚合 SUM(salary) GROUP BY department 组内整体
SUM() OVER() 窗口 SUM(salary) OVER (PARTITION BY department ORDER BY id) 逐行计算

示例

-- 使用 GROUP BY 计算部门工资总和(结果少于原始行数)
SELECT department, SUM(salary) FROM employees GROUP BY department;

-- 使用窗口函数计算部门工资总和(结果和原始行数相同)
SELECT id, name, department, salary,
       SUM(salary) OVER (PARTITION BY department) AS department_total
FROM employees;

5. 复杂应用案例

案例:计算累计销售额占比

WITH sales_ranked AS (
    SELECT order_id, customer, amount,
           SUM(amount) OVER () AS total_sales,
           SUM(amount) OVER (ORDER BY amount DESC) AS running_total
    FROM sales
)
SELECT *, (running_total / total_sales) AS percentage FROM sales_ranked;

计算累计销售额占总销售额的比例,帮助分析 80/20 规则(帕累托分析)。


6. 总结

  • 窗口函数不会减少数据行数,而是对每一行进行计算。
  • OVER() 语法决定窗口范围
    • PARTITION BY 进行分区;
    • ORDER BY 控制计算顺序;
    • ROWS / RANGE 进一步控制计算范围。
  • 常见窗口函数
    • 排名:RANK()DENSE_RANK()ROW_NUMBER()
    • 统计:SUM()AVG()COUNT()
    • 偏移:LAG()LEAD()FIRST_VALUE()

窗口函数是 数据分析复杂查询 的强大工具,掌握它能极大提升 SQL 处理能力!

你可能感兴趣的:(mysql,mysql,数据库)