前言
假设你有一张表,里面记录了各个城市的销售数据,包括城市、销售日期和销售额。你可能会使用GROUP BY
来按城市对数据进行分组,这样就可以知道每个城市的总销售额了。但是,有时候你可能还会希望对每个城市的销售数据进行更细致的分析。比如,你想知道每个城市中每天销售额最高的记录是哪条,那么直接来个Max()函数就可以实现,但是你想计算每个城市的销售额占整个组的比例,就需要将处理的细度细分到组内的元素,这里就需要用到窗口函数啦
窗口函数介绍
基础概念
MySQL 8.0 新增窗口函数,窗口函数又被称为开窗函数,与oracle 窗口函数类似,属于MysQL的一大特点
窗口函数可以让你在GROUP BY
之后对每个组内的数据进行特定的操作,而不仅仅是简单地进行分组求和或者平均值计算。
分类
语法结构
函数详解
序号函数
-
函数可以用来实现分组排序,并添加序号
- ROW_NUMBER(): 对组内元素进行添加编号,根据排序字段从1开始编号,同数量下无并列号情况
- RANK(): 对组内元素进行添加编号,根据排序字段从1开始编号,同数量下有并列号情况,自动跳过并列号原始序号
- DENSE_RANK(): 对组内元素进行添加编号,根据排序字段从1开始编号,同数量下有并列号情况,不跳过并列号原始序号
-
语法格式
ROW_NUMBER() | RANK() | DENSE_RANK() OVER(
PARTITION BY .... # 选填,分组字段,不加则表示全局排序
ORDER BY ... # 必填,排序字段
) # 结果是作为一个字段进行返回
-
案例演示
-
使用注意
- 对于序号函数的结果字段无法通过WHERE来进行过滤,因为SQL的执行是先执行FROM,再执行WHERE,最后才会执行SELECT,所以在WHERE中无法获得SELECT中的序号函数的结果字段来进行过滤。因此我们只能通过子查询来进行过滤
开窗聚合函数
注意噢,这里是针对组内的每一条数据以及其上方的数据进行一个再细分的分组计算,这比我们传统的分组聚合函数粒度更加细
-
在组内进行集合计算,在窗口中每条记录动态地应用聚合函数 (SUM()、AVG()、MAX()、MIN()、COUNT()),可以动态计算在指定的窗口内的各种聚合函数值。
- SUM(): 求组内元素总和
- AVG(): 求组内元素平均值
- MAX(): 求组内元素最大值
- MIN(): 求组内元素最小值
- COUNT(): 求组内元素条数
-
语法格式
SUM() | AVG() | MAX() | MIN() | COUNT() OVER(
PARTITION BY .... # 选填,分组字段,不加则表示全局排序
ORDER BY ... # 必填,排序字段
ROWS BETWEEN 长度A preceding AND CURRENT ROW # 选填,以当前行向上A行作为计算区间,默认是从组内首行到当前行的区间范围
ROWS BETWEEN 长度A preceding AND 长度B FOLLOWING # 选填,以当前行向上A行及其当前行向下B行作为计算区间
ROWS BETWEEN 长度A preceding AND UNBOUNDED FOLLOWING # 选填,以当前行向上A行到组内最后一行作为计算区间
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING # 选填,以当前行到组内最后一行作为计算区间
) # 结果是作为一个字段进行返回
- 案例演示
分布函数
CUME_DIST
- 查找分组内
小于、等于当前数据的排序字段的行数 / 分组内总行数
- 应用场景: 查询小于等于当前薪资 (salary)的比例
- 语法格式
- 案例演示
PERCENT_RANK(了解)
- 用途:每行按照公式
(rank-1) / (rows-1)
进行计算。其中,rank为 RANK() 函数产生的序号,rows为当前窗口的记录总行数
- 语法格式
- 案例演示
前后函数
- 用途: 获取组内距离自己前面多少行或者后面多少行的数据放到自己行上,方便进行数值运算
说人话就是把组内其他行的那个排序字段的数据转到自己这行上来了,既然都在一个行上了,那么可以实现数值运算,简而言之就是组内两两数据间的数值运算的效果
- 应用场景: 查询前1名同学的成绩和当前同学成绩的差值
- 语法格式
- 案例演示
头尾函数
- 用途: 返回组内从首行到当前行这个区间的第一个数据或最后一个数据(这个其实就是本行的数据)
- 应用场景: 截止到当前,按照日期排序查询第1个入职和最后1个入职员工的薪资
- 语法格式
- 案例演示
其他函数
NTH_VALUE
- 用途: 返回分组区间的首行到当前行的 第n个expr的值。expr可以是表达式,也可以是列名
- 应用场景: 截止到当前薪资,显示每个员工的薪资中排名第2或者第3的薪资
- 语法格式
- 案例演示
NTILE
- 用途: 将分区中的有序数据分为n个等级,记录等级数
- 应用场景: 将每个部门员工按照入职日期分成3组
- 语法格式
- 案例演示