MySQL数据库中的窗口函数示例详解

 更新时间:2026年11月10日 11:25:36   作者:梦想不只是梦与想  
窗口函数允许用户在查询结果集的一个子集上执行计算,这个子集被称为窗口,这篇文章主要介绍了MySQL数据库中窗口函数的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

窗口函数是 MySQL 8.0 引入的一个重要特性,它可以在不改变数据行数的前提下,对每一行数据进行聚合、排名、累积等计算。与 GROUP BY 不同,窗口函数会保留所有原始行。

一、窗口函数

窗口函数的执行逻辑是:在每一行数据上,基于“窗口”(一个定义好的数据范围)进行计算,然后把计算结果的附加列(如排名、累计值等)直接写到对应的行上,不合并行。

语法结构

SELECT
    列名,
    窗口函数() OVER (
        PARTITION BY 分区列    -- 分组
        ORDER BY 排序列        -- 排序
        ROWS/RANGE BETWEEN ... -- 窗口范围
    ) AS 别名
FROM 表名;

二、窗口函数的三大类别

1. 排名函数

函数说明
ROW_NUMBER()按顺序编号,不处理并列(1,2,3,4...)
RANK()跳跃排名,并列后跳过(1,1,3,4...)
DENSE_RANK()连续排名,并列后不跳过(1,1,2,3...)
NTILE(n)将数据分成 n 组,返回组号

示例:按成绩排名

-- 创建示例表
CREATE TABLE students (
    id INT,
    name VARCHAR(50),
    score INT,
    class VARCHAR(10)
);

INSERT INTO students VALUES
(1, 'Alice', 95, 'A'),
(2, 'Bob', 85, 'A'),
(3, 'Charlie', 95, 'A'),
(4, 'David', 78, 'B'),
(5, 'Eva', 92, 'B'),
(6, 'Frank', 85, 'B');

-- 各排名函数的对比
SELECT 
    name,
    score,
    ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num,
    RANK() OVER (ORDER BY score DESC) AS rank,
    DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank,
    NTILE(3) OVER (ORDER BY score DESC) AS ntile
FROM students;

结果:

+---------+-------+---------+------+------------+-------+
| name    | score | row_num | rank | dense_rank | ntile |
+---------+-------+---------+------+------------+-------+
| Alice   | 95    | 1       | 1    | 1          | 1     |
| Charlie | 95    | 2       | 1    | 1          | 1     |
| Eva     | 92    | 3       | 3    | 2          | 2     |
| Bob     | 85    | 4       | 4    | 3          | 2     |
| Frank   | 85    | 5       | 4    | 3          | 3     |
| David   | 78    | 6       | 6    | 4          | 3     |
+---------+-------+---------+------+------------+-------+

区别:

  • ROW_NUMBER():1,2,3,4,5,6

  • RANK():1,1,3,4,4,6

  • DENSE_RANK():1,1,2,3,3,4

  • NTILE(3):1,1,2,2,3,3

2. 聚合函数(作为窗口函数)

函数说明
SUM()窗口内的累计和
AVG()窗口内的平均值
COUNT()窗口内的行数
MAX() / MIN()窗口内的最大值/最小值

示例:累计求和与移动平均

SELECT 
    date,
    sales,
    SUM(sales) OVER (ORDER BY date) AS cumulative_sales,
    AVG(sales) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg_3
FROM sales_data;

3. 取值函数

函数说明
LAG()获取当前行之前的第 N 行
LEAD()获取当前行之后的第 N 行
FIRST_VALUE()窗口内的第一行
LAST_VALUE()窗口内的最后一行

示例:计算环比增长率

SELECT 
    month,
    revenue,
    LAG(revenue, 1) OVER (ORDER BY month) AS prev_month_revenue,
    ROUND(
        (revenue - LAG(revenue, 1) OVER (ORDER BY month)) / 
        LAG(revenue, 1) OVER (ORDER BY month) * 100, 2
    ) AS growth_rate_percent
FROM monthly_revenue;

三、PARTITION BY(分组计算)

PARTITION BY 将数据分组,窗口函数在每个分组内独立计算。

SELECT 
    class,
    name,
    score,
    RANK() OVER (PARTITION BY class ORDER BY score DESC) AS rank_in_class
FROM students;

结果:

+-------+---------+-------+---------------+
| class | name    | score | rank_in_class |
+-------+---------+-------+---------------+
| A     | Alice   | 95    | 1             |
| A     | Charlie | 95    | 1             |
| A     | Bob     | 85    | 3             |
| B     | Eva     | 92    | 1             |
| B     | Frank   | 85    | 2             |
| B     | David   | 78    | 3             |
+-------+---------+-------+---------------+

四、窗口范围(Frame)

窗口范围决定计算时包含哪些行:

写法说明
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW从开始到当前行(默认累计)
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW当前行及前 2 行
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING前 1 行 + 当前行 + 后 1 行
ROWS UNBOUNDED PRECEDING从开始到当前行的简写
RANGE BETWEEN ...基于值的范围(而不是行数)
SELECT 
    date,
    sales,
    SUM(sales) OVER (ORDER BY date) AS cumulative,                  -- 默认从开始到当前
    SUM(sales) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS last_3_days,
    SUM(sales) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS total_all
FROM sales_data;

五、窗口函数 vs GROUP BY

对比维度GROUP BY窗口函数 OVER()
行数变化合并行,行数减少保持原行数
结果位置单独的结果行附加在原行旁边
子查询需求常需要子查询不需要
适用场景汇总统计排名、累计、移动平均
-- GROUP BY:只能看到汇总结果
SELECT department, AVG(salary) FROM employees GROUP BY department;

-- 窗口函数:每行都保留,同时显示平均工资
SELECT 
    employee_id,
    name,
    department,
    salary,
    AVG(salary) OVER (PARTITION BY department) AS dept_avg_salary
FROM employees;

到此这篇关于MySQL数据库中窗口函数的文章就介绍到这了,更多相关MySQL窗口函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL数据库JDBC编程详解流程

    MySQL数据库JDBC编程详解流程

    JDBC是指Java数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库。从根本上来说,JDBC 是一种规范,它提供了一套完整的接口,允许便携式访问到底层数据库,本篇文章我们来了解MySQL连接JDBC的流程方法
    2022-01-01
  • mysql之如何查找配置文件my.ini的位置

    mysql之如何查找配置文件my.ini的位置

    这篇文章主要介绍了mysql之如何查找配置文件my.ini的位置问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • mysql中left join设置条件在on与where时的用法区别分析

    mysql中left join设置条件在on与where时的用法区别分析

    这篇文章主要介绍了mysql中left join设置条件在on与where时的用法区别,结合实例形式分析了mysql中left join设置条件在on与where时的相关用法区别与操作注意事项,需要的朋友可以参考下
    2020-02-02
  • MySQL中的binary类型使用操作

    MySQL中的binary类型使用操作

    这篇文章主要介绍了MySQL中的binary类型使用操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • MySQL递归CTE案例解析

    MySQL递归CTE案例解析

    MySQL 8.0 引入的递归CTE(公共表表达式),为层级数据查询提供了简洁高效的解决方案,本文将从基础概念出发,逐步深入递归CTE的语法、实战场景、常见问题与优化技巧,帮助你彻底掌握这一强大工具,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • 一文彻底吃透MySQL内置函数日期、字符串、数学函数(实战案例)

    一文彻底吃透MySQL内置函数日期、字符串、数学函数(实战案例)

    MySQL中日期查询的核心是正确使用日期函数和比较操作符,关键在于理解日期格式、时区影响以及索引是否生效,这篇文章主要介绍了MySQL内置函数日期、字符串、数学函数的相关资料,需要的朋友可以参考下
    2026-08-08
  • MySQL 覆盖索引的优点

    MySQL 覆盖索引的优点

    当索引包含了所有查询的数据时,这个索引就称之为覆盖索引。覆盖索引能够成为一个非常有力的工具并且能够显著改善性能,本文将具体讲述覆盖索引的优点
    2021-05-05
  • win10下mysql 8.0.18 安装配置方法图文教程(windows版)

    win10下mysql 8.0.18 安装配置方法图文教程(windows版)

    这篇文章主要介绍了windows版的mysql 8.0.18 安装配置方法图文教程,文中安装步骤介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-11-11
  • 与MSSQL对比学习MYSQL的心得(五)--运算符

    与MSSQL对比学习MYSQL的心得(五)--运算符

    MYSQL中的运算符很多,这一节主要讲MYSQL中有的,而SQLSERVER没有的运算符
    2014-06-06
  • 教您修复mysql数据库的方法

    教您修复mysql数据库的方法

    你可能在使用MySQL过程中,各种意外导致数据库表的损坏,而且这些数据往往是最新的数据,通常不可能在备份数据中找到。本章将继上篇文章中检查出表的问题后,告诉你如何修复表
    2014-05-05

最新评论