您的位置:首页 > 手游攻略 > MySQL数据库中的窗口函数示例完整指南

MySQL数据库中的窗口函数示例完整指南

作者:互联网  时间: 2026-11-11 08:50:01  

平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“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;

相关资讯

最新游戏

更多

Copyright©2010-2019. All rights reserved | 波波三国游戏官网|[email protected]

备案编号:湘ICP备2022015115号-4