MySQL数据库专栏:
简书:https://www.jianshu.com/nb/42057860
知乎:https://zhuanlan.zhihu.com/791072385mysql
一、窗口函数概念
窗口函数又叫做分析函数,在Oracle中已经早就又了,这次MySQL从5.x升级到8.x其中一个特性就是开始支持窗口函数了。在MySQL不支持窗口函数之前,一直采用变量的方式来模拟窗口函数的实现,虽然效率还行,但是代码看上去并不简单。
首先要理解窗口函数是干什么用的?当我们处理既要分组时,又要对分组内的数据进行排序的时候,我们就可以使用窗口函数。
窗口函数和普通聚合函数很容易混淆,二者区别如下:
- 聚合函数是将多条记录聚合为一条;而窗口函数是每条记录都会执行,有几条记录执行完还是几条。
- 聚合函数也可以用于窗口函数中。
二、具体例子
通常我们一般使用的比较多的是窗口函数中的序号函数:row_number() / rank() / dense_rank(),那这三个函数能起到的作用如下:
//例子来自leetCode中高赞题解(TopN分组排序问题)
https://leetcode-cn.com/problems/department-top-three-salaries/solution/tu-jie-sqlmian-shi-ti-jing-dian-topnwen-ti-by-houz/
//还可以使用over(partition by 分组 order by 字段)实现先分组后排序
select *,
rank() over (order by 成绩 desc) as ranking,
dense_rank() over (order by 成绩 desc) as dese_rank,
row_number() over (order by 成绩 desc) as row_num
from 班级;
得到结果:
从上面的结果可以看出:
1)rank函数:这个例子中是5位,5位,5位,8位,也就是如果有并列名次的行,会占用下一名次的位置。比如正常排名是1,2,3,4,但是现在前3名是并列的名次,结果是:1,1,1,4。
2)dense_rank函数:这个例子中是5位,5位,5位,6位,也就是如果有并列名次的行,不占用下一名次的位置。比如正常排名是1,2,3,4,但是现在前3名是并列的名次,结果是:1,1,1,2。
3)row_number函数:这个例子中是5位,6位,7位,8位,也就是不考虑并列名次的情况。比如前3名是并列的名次,排名是正常的1,2,3,4。
三、总结
面对一些既要分组又要排序的TOP N问题,我们可以使用窗口函数快速得出结果.
# topN问题 sql模板
select *
from (
select *,
row_number() over (partition by 要分组的列名
order by 要排序的列名 desc) as 排名
from 表名) as a
where 排名 <= N;