MySQL能否使用窗口函数?详解其强大功能

mysql可以使用窗口函数么

时间:2025-07-10 08:31


MySQL中的窗口函数:强大的数据分析工具 在数据库管理和数据分析领域,MySQL作为一个广泛使用的开源关系型数据库管理系统,其功能随着版本的更新而不断扩展和完善

    其中,窗口函数(Window Functions)的引入是MySQL8.0及更高版本中的一个重要里程碑

    这些函数极大地丰富了MySQL的数据分析能力,使得用户能够在不改变数据行数的情况下,对数据进行复杂的计算和排名

    本文将深入探讨MySQL中的窗口函数,展示其强大的功能和实际应用场景

     一、窗口函数的基本概念 窗口函数是一种SQL函数,它允许在结果集的“窗口”内进行计算

    这个“窗口”是由一组行构成的,这些行与当前行有某种关系(如相邻、属于同一分组等)

    窗口函数与聚合函数类似,但关键在于窗口函数不会将多行合并为一行,而是为结果集中的每一行返回一个值

     MySQL中的窗口函数基本语法如下: sql function_name() OVER( 【PARTITION BY column_list】 【ORDER BY column_list】 【frame_clause】 ) -`function_name`:窗口函数的名称,如`ROW_NUMBER()`、`RANK()`、`SUM()`等

     -`PARTITION BY`:可选,用于定义行分组的方式,类似于`GROUP BY`,但`PARTITION BY`不会减少行数

     -`ORDER BY`:可选,用于定义分区内行的排序方式

     -`frame_clause`:可选,用于定义当前分区内的行子集(窗口帧),精确控制窗口函数计算时包含的行的集合

     二、常用窗口函数及其应用场景 1.排名函数 -`ROW_NUMBER()`:为结果集中的每一行分配一个唯一的整数序号

    这个函数非常适用于需要为数据集中的每一行生成一个唯一标识的场景

     示例: sql SELECT employee_id, first_name, last_name, salary, ROW_NUMBER() OVER(ORDER BY salary DESC) AS row_number FROM employees; 该查询按工资降序为每位员工分配一个唯一的序号

     -`RANK()`:与`ROW_NUMBER()`类似,但在具有相同值的行中使用相同的序号,并在下一个序号时跳过重复的序号

    这个函数适用于需要为数据集中的行分配排名,且排名需要跳过重复值的场景

     示例: sql SELECT employee_id, first_name, last_name, salary, RANK() OVER(ORDER BY salary DESC) AS rank FROM employees; 该查询按工资降序为员工分配排名,工资相同的员工将获得相同的排名,但后续排名会跳跃

     -`DENSE_RANK()`:与`RANK()`类似,但不会跳过重复的序号

    这个函数适用于需要为数据集中的行分配排名,且排名不希望跳过重复值的场景

     示例: sql SELECT employee_id, first_name, last_name, salary, DENSE_RANK() OVER(ORDER BY salary DESC) AS dense_rank FROM employees; 该查询按工资降序为员工分配排名,工资相同的员工将获得相同的排名,且后续排名连续不跳跃

     实际应用场景:假设我们要找出每个部门薪资最高的3名员工,可以使用`ROW_NUMBER()`函数结合`PARTITION BY`子句来实现

     2.分布函数 -`CUME_DIST()`:计算当前行在结果集中的累计分布

    这个函数返回小于或等于当前行值的行在分区内所占的比例,值范围在(0,1】之间

     示例: sql SELECT emp_name, dept_name, salary, CUME_DIST() OVER(PARTITION BY dept_name ORDER BY salary ASC) AS salary_cume_dist FROM employees; 该查询计算工资低于或等于当前员工工资的人数占部门总人数的比例

     -`PERCENT_RANK()`:计算当前行在结果集中的百分比排名

    这个函数返回当前行在分区内的相对排名(百分比形式),值范围在0到1之间

     示例: sql SELECT emp_name, dept_name, salary, PERCENT_RANK() OVER(PARTITION BY dept_name ORDER BY salary ASC) AS salary_percent_rank FROM employees; 该查询计算每个员工工资在其部门内的百分位排名

     3.偏移函数 -`LEAD()`:获取当前行后面的第N行的值

    这个函数允许我们访问当前行之后的数据行,非常适用于计算同比增长率等场景

     示例: sql SELECT date, sales, LEAD(sales) OVER(ORDER BY date) AS next_day_sales FROM daily_sales; 该查询获取当前日期之后的销售额

     -`LAG()`:获取当前行前面的第N行的值

    这个函数允许我们访问当前行之前的数据行

     示例: sql SELECT date, sales, LAG(sales) OVER(ORDER BY date) AS previous_day_sales FROM daily_sales; 该查询获取当前日期之前的销售额

     4.值函数 -`FIRST_VALUE()`:获取窗口中的第一行的值

    这个函数返回指定窗口内的第一行的值

     -`LAST_VALUE()`:获取窗口中的最后一行的值

    这个函数返回指定窗口内的最后一行的值

     -`NTH_VALUE()`:获取窗口中的第N行的值

    这个函数返回指定窗口内的第N行的值

     5.聚合窗口函数 聚合函数如`SUM()`、`AVG()`等也可以作为窗口函数使用,用于计算累计总和、移动平均值等

     示例: sql SELECT employee_id, first_name, last_name, salary, SUM(salary) OVER(ORDER BY employee_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_salary FROM employees; 该查询计算每个员工的累积工资,从分区开始到当前行的所有行都被包括在内

     三、窗口范围(Window Frame) 窗口范围是窗口函数中的一个重要概念,用于定义在计算窗口函数时所使用的行集合

    通过指定窗口范围,可以精确控制哪些行被包括在窗口函数的计算中

     常见的窗口范围类型包括: -`ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`:包括从分区的第一行到当前行的所有行

     -`ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING`:包括从当前行到分区的最后一行的所有行

     -`ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING`:包括分区中的所有行

     -`ROWS BETWEEN N PRECEDING AND M FOLLOWING`:包括从当前行向前N行到当前行向后M行的所有行

     此外,还可以使用`RANGE`子句来定义基于逻辑值范围的窗口,这通常依赖于`ORDER BY`列

    在处理重复值时,`ROWS`和`RANGE`的行为可能会有所不同

     四、实际应用案例 1.学生成绩排名 假设我们有一个学生成绩表`student_scores`,包含学生的姓名和成绩

    我们可以使用`RANK()`和`DENSE_RANK()`函数来为学生的考试成绩进行排名,并展示两者的区别

     sql CREATE TABLE student_scores( id