窗口函数,也叫OLAP函数(Online Anallytical Processing,联机分析处理),可以对数据库数据进行实时分析处理。
MySQL从8.0版本开始支持窗口函数了,这里以MySQL为例来介绍这个窗口函数的。
窗口函数是什么
窗口其实是指一个记录集合,而窗口函数则是在满足某些条件的记录集合上执行指定的函数方法。
在日常工作中比较常见的例子比如求学生的单科成绩排名、求前三名等等之类的。
窗口函数的基本语法如下:
1 | <窗口函数> OVER (PARTITION BY <用于分组的列名> ORDER BY <用于排序的列名>) |
像一些聚合函数如 SUM()
、AVG()
、COUNT()
、MAX()
与MIN()
等等,以及专用的窗口函数RANK()
、DENSE_RANK()
与ROW_NUMBER()
等等。
排序函数
就是进行排序操作,显示排名
1 | RANK()`、`DENSE_RANK()`与`ROW_NUMBER() |
先创建数据表如下:
1 | DROP TABLE |
这是一张成绩表,分别是学号、姓名、科目与得分。
面对上面这份数据,要求各科目学生们得分排名,就可以用到排序函数。
比如RANK()
1 | SELECT |
这个操作是按照科目进行分组,然后按照得分进行排序(DESC
是由大到小)。
结果如下:
可以看到,对于同样得分而言,RANK()
下的名次是同样的,而且名次中存在间隙(不一定连续)。
来看RANK()
、DENSE_RANK()
与ROW_NUMBER()
三者的差异:
1 | SELECT |
结果对比如下:
可以看到这三者的作用如下:
函数 | 说明 |
---|---|
ROW_NUMBER | 为表中的每一行分配一个序号,可以指定分组(也可以不指定)及排序字段(连续且不重复) |
DENSE_RANK | 根据排序字段为每个分组中的每一行分配一个序号。排名值相同时,序号相同,序号中没有间隙(1,1,1,2,3这种) |
RANK | 根据排序字段为每个分组中的每一行分配一个序号。排名值相同时,序号相同,但序号中存在间隙(1,1,1,4,5这种) |
要获取各科目排名第一的学生及得分,就可以再加个条件判断即可,需要注意这里用到了子查询。
1 | SELECT |
查询结果如下:
另外还有个NTILE(n)
将分区中的有序数据分为n个等级,记录等级数
比如按照学号分区得分排序进行分2个等级
1 | SELECT |
查询结果如下:
NTILE(n)
在数据分析中应用较多,比如由于数据量大,需要将数据平均分配到n个并行的进程分别计算,此时就可以用NTILE(n)
对数据进行分组(由于记录数不一定被n整除,所以数据不一定完全平均),然后将不同桶号的数据再分配。
分布函数
分布函数有两个PERCENT_RANK()
和CUME_DIST()
PERCENT_RANK()
的用途是每行按照公式(rank-1) / (rows-1)
进行计算。其中,rank
为RANK()函数
产生的序号,rows为当前窗口的记录总行数。
1 | SELECT |
查询结果如下:
CUME_DIST()
的用途是分组内小于、等于当前rank值的行数 / 分组内总行数。
查询小于等于当前成绩的比例
1 | SELECT |
查询结果如下:
可以看到,数学科目中有0.5也就是50%的朋友得分120,超过66.66%的学生成绩在118分及以上。
前后函数
查询当前行指定字段往前后N行数据,LAG()
和 LEAD()
前N行LAG(expr[,N[,default]])
,比如看各科目同学每个人往前3名的同学得分。
1 | SELECT |
查询结果如下:
可以看到,各科目前三行都是NULL空值,这是因为前三行不存在它们往前3行的值。rank 4的前3是rank 1,对应得分是120。
这个可以用于进行一些诸如环比的情况,在这里可以计算当前同学与前1名同学得分差值,操作如下:
1 | SELECT |
查询结果如下:
LEAD(expr[,N[,default]])
就是往后N名了,这里就不再赘述。
首尾函数
查询指定字段第一或最后的数据FIRST_VALUE(expr)
和LAST_VALUE(expr)
查询各科目得分第1的分值
1 | SELECT |
查询结果如下:
可以计算各个同学与第1名的差距(上面前后函数部分介绍了和前1名的差距):
1 | SELECT |
查询结果如下:
LAST_VALUE(expr)
就是最后1名了,这里不再赘述。
另外还有NTH_VALUE(expr, n)
查询指定字段有序行的第n的值
比如查询排名第4的数据
1 | SELECT |
查询结果如下:
聚合函数
在窗口中每条记录动态地应用聚合函数(SUM()
、AVG()
、MAX()
、MIN()
、COUNT()
),可以动态计算在指定的窗口内的各种聚合函数值。
所以,这里构造一个带有时间字段的数据表。
1 | DROP TABLE |
这是一张语文成绩表,分别是学号、姓名、时间与得分。
比如,要查询在截止每个时间语文最高分,可以这样操作:
1 | SELECT |
查询结果如下:
以上就是基础介绍,日常工作的的实际操作应该会更加复杂。