当前位置:网站首页 > 技术博客 > 正文

mysql窗口函数使用方法



牛逼的兄弟两个月前教了我一招......

2023年12月下旬,广东终于冷了!回想直到12月15那天,依然穿着短袖上班,吹着风扇空调睡觉… 哈哈,这是截至发文时的一些感受与题外话。天气是冷了,但心中依然热情似火,一是工作业务上又有稍微复杂的业务,有挑战;二是虽然有挑战,但想起牛逼的兄弟@CaptinKoo两个月前教了我一招:SQL窗口函数,业务难题迎刃而解!趁着这次解决难题的热度,将本次学到的窗口函数知识点以及项目实战记录下来,供各位分享。

我个人学习窗口函数主要有两个用处:一是对现有SQL知识的拓展,二是能使用窗口函数对一些特定场景做SQL简化,解决复杂问题。

但在正式开始之前,得事先说明一个前提:
前提

  • 窗口函数是 Mysql 8 的新特性。本文的学习与演示,都基于Mysql 8
  • 学习窗口函数,建议有一定的SQL基础

学习目标

  • 学习并了解SQL窗口函数相关概念
  • 能使用SQL窗口函数解决部分业务场景题目,项目实战
  • 若实际业务用得少,那上述知识了解一下即可,建议收藏本文,用到的时候可以翻出来参考

下面我们开始!

这一小节我们介绍窗口函数的一些概念。

概念
窗口函数,也叫OLAP函数(Online Anallytical Processing,联机分析处理),可以对数据库数据进行实时分析处理。

窗口函数在MySQL 8中引入,是Mysql 8的新特性。是一种主要用于数据分析、特定字段分组等的一种特殊的函数。

常见使用场景

  • 数据分析,如排名、排序、分组统计、计算、前后值比较等
  • 对某些分组场景简化SQL,提升效率
  • 常用于子查询,将一些复杂条件简化

窗口函数的语法如下:

 
  
  • 子句用于指定分组列,关键字: 。
  • 子句用于指定排序列,关键字 。
  • 子句用于指定窗口的范围,关键字 即[开始行]、[结束行](这部分在“补充与总结”小节中作补充详细说明)。

其中, 子句在实际中可能用得相对少一些,因此有部分参考资料的语法描述省略了 子句,主要侧重于分组与排序:

 
  

也正因此,本文将 子句相关关键字知识点将会以补充的形式说明,而侧重常用窗口函数的学习与练习,侧重 子句与子句的使用。

语法举例,设有Order表,查询销售数量总和及其当前行前两行和后两行的销售数量总和:

 
  

这个例子暂时看不懂个没关系,接下来,我们会详细介绍常见窗口函数,并在介绍的过程中举例。之后,上述例子就很好理解了。

本小节介绍常见窗口函数。

若要跟着本文进行练习,则可以参考着创建如下表,本文的例子均基于下表:

设计一个销售数据表。该表包含以下字段:

  • id :销售记录的唯一标识符(主键)
  • product :产品名称
  • category :产品类别
  • sale_date :销售日期
  • quantity :销售数量
  • revenue :销售收入

以下是创建表的以及 插入模拟数据的

 
  

好的,准备工作完成,下面我们一边学习具体窗口函数并练习吧!

1.3.1 聚合窗口函数

许多窗口函数的教程,通常将常用的窗口函数分为两大类:聚合窗口函数 与 专用窗口函数。聚合窗口函数的函数名与普通常用聚合函数一致,功能也一致。从使用的角度来讲,与普通聚合函数的区别在于提供了窗口函数的专属子句,来使得数据的分析与获取更简便。主要有如下几个:

函数名 作用 SUM 求和 AVG 求平均值 COUNT 求数量 MAX 求最大值 MIN 求最小值

区别
这个例子演示与普通聚合函数的区别。设我们要求使用一条查询语句,在sales表每行最后一列都加上这一行的产品类别 的 平均 销售收入,并且以顺序排序,即如下图所示:
00

  • 普通聚合函数的一种解法:
 
  
  • 聚合窗口函数:
 
  

这么一对比,窗口聚合函数简单不少!

1.3.2 专用窗口函数

常见的专用窗口函数

函数名 分类 说明 RANK 排序函数 类似于排名,并列的结果序号可以重复,序号不连续 DENSE_RANK 排序函数 类似于排名,并列的结果序号可以重复,序号连续 ROW_NUMBER 排序函数 对该分组下的所有结果作一个排序,基于该分组给一个行数 PERCENT_RANK 分布函数 每行按照公式 进行计算 CUME_DIST 分布函数 分组内小于、等于当前 rank 值的行数 / 分组内总行数

练习
分别对上述表格常见的专用窗口函数进行调用,查看结果。

 
  

01

至于其它专用窗口函数,请读者自行查阅其它资料做拓展。

通过对上面我们对窗口函数的学习与练习,我们一来明白了窗口函数的相关概念、常见窗口函数的使用以及这些窗口函数的作用与效果。也通过窗口函数与一般函数子查询作了一个简单的对比,体现了窗口函数在一些特定需求的强大。那么既然窗口函数如此强大,那么窗口函数的性能对比传统函数、传统子查询与分组的性能相比如何呢?

窗口函数的性能和其它SQL语句一样,受数据量大小、分区复杂度情况等影响。同等数量级的一般情况下:

  • 窗口函数本身内嵌分组,相当于把条件先筛了一遍,可减少部分子查询。减少的子查询部分相当于降低了子查询本身的连接消耗。
  • 窗口函数窗口大小限制,可减少部分行数结果返回消耗。
  • 窗口函数可用于子查询,简化部分语句。但又因为用在了子查询,还是有一定连接开销。
  • 窗口聚合函数在窗口函数原有分区、排序的基础上增加了聚合,且因不会影响行数的关系,比原有分组行数要多,其开销比一般聚合函数开销要大一些,因此窗口聚合函数一般情况下会比普通聚合函数性能差一些。

上一小节,我们学习了 SQL 窗口函数的概念,从本小节开始,就是做题练习与实战了!

接下来要列举例题,是 @CaptinKoo 两个月前教我们窗口函数时提供的练习题。让我们跟随 @CaptinKoo 老师的脚步,进行窗口函数练习吧!

题目链接
LeetCode-SQL178分数排名链接

题目描述
05

06

题解
根据题目描述,我们得知,返回结果序号可重复,连续,因此我们使用DENSE_RANK()函数。

 
  

题目链接
LeetCode-SQL184部门工资最高的员工

题目描述

07
08

题解
根据描述,我们可以通过 RANK 窗口函数对 Employee 表进行排序,获取 rank 值为1 的 员工并关联到部门表。

 
  

题目链接
LeetCode-SQL185部门工资前三高的所有员工

题目描述

03

04

题解
有了上面两道题的解题练习,这道题也迎刃而解:

 
  

太棒了!我们一下就完成了三道包括中等、困难难度的LeetCode题目,接下来,我们可以将我们学习并练习过的知识点用于项目实战了!

本小节是我个人用窗口函数解决实际工作问题的实战记录。涉及的表、字段均已做描述更换,脱敏处理。

已知用户订单评价表有如下字段:

字段名 类型 说明 id bigint 评价表主键id evaluate text 评价内容 user_id bigint 用户id update_time datetime 更新时间 order_id bigint 订单id

其中,每个订单可以有多个评价,每个评价都可以修改。业务需要,需要获取当前用户所有订单最近一次评价内容,并返回订单id、最近一次评价的内容。

此次实战业务需要根据获取最近一次评论并根据进行分组。

在尚未系统学习窗口函数时,我们第一时间会想到的是传统子查询。

但毕竟实际业务远比这里的脱敏描述要复杂,一时间难以实现,于是我第一时间回顾了@CaptinKoo大佬教我的窗口函数并解决:

 
  

这条SQL是通过ROW_NUM()函数将工单评价表根据工单分组,更新时间倒序并给它一个行序号。行序号1的就是我们要求的结果。

你能想到用传统子查询实现相同功能的SQL吗?

关键字及其含义表

关键字 含义 PRECEDING 当前行数往前 FOLLOWING 当前行数往后 CURRENT ROW 当前行 UNBOUNDED 起点(一般结合PRECEDING,FOLLOWING使用) UNBOUNDED PRECEDING 表示该窗口最前面的行(起点) UNBOUNDED FOLLOWING 表示该窗口最后面的行(终点)

此表的知识内容来自于参考文章

根据这个关键字含义表,读者可以理解文初提到的例子了吗?

可选挑战题目
这里提供一题可选的挑战题目链接,是LeetCode困难题目,依然来自@CaptinKoo大佬的推荐,此题的一种解法用到子句。

LeetCode-601体育馆的人流量

既然这种函数叫"窗口函数",那么它应该可以像"窗口"一样,通过滚动的方式,获取一定范围内的视图。

而滚动的方式恰恰就是子句。通过子句,获取窗口函数结果的范围,从而有给用户"窗口"的感觉。

  • RANGE 基于排序列的值定义帧
  • ROWS 基于行数定义帧,不考虑排序列

由于两者用法相似,且一般 子句会用得多一些,因此本文的语法概述忽略了子句。此处作为补充,供读者参考。

本文借由好兄弟@CaptinKoo两个月前教过我的窗口函数知识,截至发文日期顺利解决一个相对比较复杂的业务的故事,记录我从CaptinKoo学到的窗口函数相关知识,以及CaptinKoo大佬推荐的相关习题,以及我个人本次实战的脱敏描述。

通过本文,我们学习到了:

  • Mysql 窗口函数相关概念:其中,语法结构是重点;
  • 常见窗口函数:聚合窗口函数、专用窗口函数(排序函数、分布函数等)
  • 相关习题与练习
  • 一个实际的练习供大佬们参考
  • 窗口函数“窗口”的体现,子句相关补充知识点
  • 知乎-窗口函数优秀参考文章1
  • 知乎-窗口函数优秀参考文章2
  • CSDN-窗口函数优秀参考文章1
  • CSDN-窗口函数优秀参考文章2

再次感谢@CaptinKoo的指导!

  • 上一篇: 获取小程序源码
  • 下一篇: hs数据库工具
  • 版权声明


    相关文章:

  • 获取小程序源码2025-06-01 07:30:05
  • ncurses linux2025-06-01 07:30:05
  • 永劫无间可以用的空白符号2025-06-01 07:30:05
  • ssh远程连接服务器,使用什么端口号2025-06-01 07:30:05
  • inner left join的区别2025-06-01 07:30:05
  • hs数据库工具2025-06-01 07:30:05
  • python 异步 asyncio2025-06-01 07:30:05
  • c++ fstream read2025-06-01 07:30:05
  • java中treenode2025-06-01 07:30:05
  • jvm调优工具2025-06-01 07:30:05