当前位置: 首页 > news >正文

MySQL 中的窗口函数详解:从入门到实战

🌟 前言

在日常开发中,我们经常需要对数据进行排序、分组、排名、累计求和等操作。传统的 GROUP BY 和子查询虽然能解决部分问题,但写法复杂、性能差,且难以处理“每组内计算”的场景。

MySQL 8.0 开始,官方正式支持了 窗口函数(Window Functions),这让复杂的数据分析变得简单高效。本文将带你全面掌握 MySQL 窗口函数的语法、常用函数及实际应用场景。


📚 一、什么是窗口函数?

1.1 定义

窗口函数(Window Function) 是一种在“结果集的一个窗口”上进行计算的函数。它不会像 GROUP BY 那样将多行合并为一行,而是为每一行都返回一个计算结果,保留原始行数。

✅ 简单理解:分组但不聚合,每行都能看到“当前组”的统计信息


1.2 与 GROUP BY 的区别

特性GROUP BY窗口函数
行数变化合并为一行保留所有行
聚合后能否访问原始列❌ 不能✅ 可以
是否支持排序内计算❌ 困难✅ 支持
典型用途统计总数、平均值排名、累计、移动平均

🔤 二、窗口函数基本语法

function_name(...) OVER ([PARTITION BY 分组字段][ORDER BY 排序字段][FRAME 子句]
)
  • function_name:如 ROW_NUMBER()SUM()AVG() 等
  • PARTITION BY:定义“窗口”范围,类似 GROUP BY
  • ORDER BY:定义窗口内的排序方式
  • FRAME:定义窗口的起始和结束行(如 ROWS BETWEEN 3 PRECEDING AND CURRENT ROW

🧰 三、常用窗口函数分类

3.1 排名函数

函数说明示例
ROW_NUMBER()行号,不重复1,2,3,4...
RANK()并列排名,留空1,2,2,4...
DENSE_RANK()并列排名,不留空1,2,2,3...
示例:学生成绩排名
SELECT name, subject, score,ROW_NUMBER() OVER (PARTITION BY subject ORDER BY score DESC) AS row_num,RANK()       OVER (PARTITION BY subject ORDER BY score DESC) AS rank_num,DENSE_RANK() OVER (PARTITION BY subject ORDER BY score DESC) AS dense_rank_num
FROM student_score;

输出:

namesubjectscorerow_numrank_numdense_rank_num
张三数学95111
李四数学90222
王五数学90322
赵六数学85443

3.2 聚合函数(作为窗口函数使用)

常见的聚合函数都可以作为窗口函数使用:

  • SUM()
  • AVG()
  • COUNT()
  • MIN() / MAX()
示例:每月累计销售额
SELECT order_month,monthly_sales,SUM(monthly_sales) OVER (ORDER BY order_month) AS cum_sales
FROM sales_summary;

输出:

order_monthmonthly_salescum_sales
2025-011000010000
2025-021500025000
2025-031200037000

3.3 值函数(前后行取值)

函数说明
LAG(col, n)向前取第 n 行的值
LEAD(col, n)向后取第 n 行的值
FIRST_VALUE(col)窗口内第一行的值
LAST_VALUE(col)窗口内最后一行的值
示例:计算每日销售额环比增长
SELECT date,sales,LAG(sales, 1) OVER (ORDER BY date) AS last_day_sales,ROUND((sales - LAG(sales, 1) OVER (ORDER BY date)) / LAG(sales, 1) OVER (ORDER BY date) * 100, 2) AS growth_rate
FROM daily_sales;

🛠 四、实战案例:客户最近一次会话查询

假设我们有一个客服系统,需求是:查询每个客户(from_account)最新的会话记录

表结构

CREATE TABLE itsm_helpdesk_session (id BIGINT,from_account VARCHAR(50),create_time DATETIME,service_status INT
);

使用窗口函数实现

SELECT *
FROM (SELECT *,ROW_NUMBER() OVER (PARTITION BY from_account ORDER BY create_time DESC) AS rnFROM itsm_helpdesk_session
) t
WHERE rn = 1;

✅ 优势:简洁、高效、易维护,避免了复杂的子查询或自连接。


⚠️ 五、注意事项与性能优化

5.1 必须使用 OVER(),否则报错

-- ❌ 错误
SELECT ROW_NUMBER() FROM table;-- ✅ 正确
SELECT ROW_NUMBER() OVER () FROM table;

5.2 合理使用索引

PARTITION BYORDER BY 字段建立复合索引,可大幅提升性能。

-- 示例
CREATE INDEX idx_session_account_time 
ON itsm_helpdesk_session(from_account, create_time DESC);

5.3 避免全表排序

如果数据量大,尽量在 WHERE 中先过滤,再使用窗口函数。

-- 推荐写法
SELECT *
FROM (SELECT *, ROW_NUMBER() OVER (...)FROM table WHERE status = 1  -- 先过滤
) t
WHERE rn = 1;

🔄 六、常见问题解答

Q1:MySQL 5.7 支持窗口函数吗?

❌ 不支持。窗口函数从 MySQL 8.0 开始引入。5.7 用户需升级或使用变量模拟(不推荐)。

Q2:窗口函数会影响性能吗?

✅ 合理使用并配合索引,性能很好。
❌ 但如果在大表上无索引使用 ORDER BY,会导致全表排序,性能极差。

Q3:可以嵌套窗口函数吗?

❌ 不可以。窗口函数不能作为其他窗口函数的参数。


📈 七、总结

特性说明
✅ 优势简化复杂查询、提升可读性、支持高级分析
❌ 限制仅 MySQL 8.0+ 支持
🔧 推荐场景排名、累计、移动平均、分组取最新
📚 学习建议多练习 ROW_NUMBER()RANK()LAG/LEAD

💡 结语

窗口函数是 SQL 进阶的必备技能,尤其在数据分析、报表开发中应用广泛。掌握它,不仅能写出更优雅的 SQL,还能显著提升查询效率。

赶快在你的 MySQL 8.0+ 环境中试试吧!


如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、转发!
也欢迎在评论区留下你的疑问或实战案例,我们一起交流进步!


📌 推荐阅读

  • 《MySQL 8.0 新特性详解》
  • 《SQL 性能优化实战》
  • 《Elasticsearch 聚合查询指南》
http://www.dtcms.com/a/364401.html

相关文章:

  • Django 命令大全:从入门到精通,开发者必备指南
  • 【QT随笔】事件过滤器(installEventFilter 和 eventFilter 的组合)之生命周期管理详解
  • 微信小程序wx.getLocation结合腾讯地图逆解析获取位置详细教程,定位授权完整流程
  • 【Qt】国际化(中英文翻译)——Qt语言家(Linguist)和QTranslator类的简单使用(内含完整源码)
  • el-tree 点击父节点无效,只能选中子节点
  • 存算一体:重构AI计算的革命性技术(3)
  • 2025 大数据时代值得考的证书排名前八​
  • 电子病历空缺句的语言学特征描述与自动分类探析(以GPT-5为例)(上)
  • 分布式AI算力系统番外篇-----超体的现实《星核》
  • 2025版基于springboot的电影购票管理系统
  • Linux_网络基础
  • Uniapp中进行微信小程序头像和昵称的更改
  • Jenkins 可观测最佳实践
  • Flutter Android真机器调式,虚拟机调试以及在Vscode中开发Flutter应用
  • 【Linux操作系统】简学深悟启示录:进程控制
  • unity中的交互控制脚本
  • 如何选择适合企业的海外智能客服系统:6 大核心维度 + 实战选型指南
  • 【STL源码剖析】从源码看 deque :拆解双端队列的底层实现与核心逻辑
  • 用友T3、T6/U8批量作废凭证
  • 从数据生成到不确定性估计:用 LSTM + 贝叶斯优化实现时间序列多步预测
  • 基于SpringBoot的旅游管理系统
  • 【大前端】React 使用 Redux 实现组件通信的 Demo 示例
  • React实现点击按钮复制操作【navigator.clipboard与document.execCommand】
  • 基于单片机PWM信号发生器系统Proteus仿真(含全部资料)
  • 平衡车 - 电机调速
  • 基于单片机车内换气温度检测空气质量检测系统Proteus仿真(含全部资料)
  • 单片机点灯
  • Linux 网络编程中核心函数`recv`。
  • zynq 开发系列 新手入门:GPIO 连接 MIO 控制 LED 闪烁(SDK 端代码编写详解)
  • Spring Boot 实现数据库表变更监听的 Redis 消息队列方案