一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情
MySQL发行8.0版本已经好几年了,一直听朋友们说有很多新特性,比如窗口函数,对于MySQL8.0的新特性我还是抱有挺大的期待的,就像java8一样,刚开始我对其爱搭不理,然后从了解到使用才发现好用啊(真香警告~)
窗口函数
为什么要有窗口函数?
答:当然是为了弥补MySQL没有的功能,弥补什么功能,我们知道group by可以分组,但是分组之后每组只能有一条数据,如果我们只是需要分组,但是每组的数据不需要合并,那这种MySQL没办法完成,而窗口函数就是为了完成这种功能的缺失。
窗口函数的官方描述:窗口函数对一组查询行执行类似聚合的操作。但是,虽然聚合操作将查询行分组为单个结果行,但窗口函数会为每个查询行生成一个结果,发生函数评估的行称为当前行,与发生函数评估的当前行相关的查询行构成当前行的窗口。
jym是不是有点懵逼,刚开始我也是,但是我跟着官网的案例,自己使用之后慢慢理解了,我先说一下我对窗口函数的理解,我认为窗口函数是介于单行和多行结果集的函数,因为窗口函数会分组,每组有多条数据,但是操作是对于这一组的,将这一组看做一条数据来执行。
我们直接上手敲代码,纸上得来终觉浅,绝知此事要躬行!
新建表dept_id
简单说一下表的结构,主要两个字段dept_id是部门Id,parent_id是上级部门id。
窗口函数语法
使用以下两种都可以:
函数 OVER ([PARTITION BY 字段名 ORDER BY 字段名 ASC|DESC])函数 OVER 窗口名 … WInDOW 窗口名 AS ([PARTITION BY 字段名 ORDER BY 字段名 ASC|DESC])注意这里WInDOW是在最后的
序号函数
1. row_number
row_number : 根据字段分组,然后排序,会生成一个序号id ,每个分区的序号互不想干且不重复。
执行如下SQL:select dept_id,parent_id,type,name,row_number() over(partition by parent_id,type order by type) as sort_id from dept;
执行结果如下:
比如根据parent_id和type分组,如果parent_id相同type为空则为两组数据,并且在同一组内的排序是递增的。
显示每个分组最靠前的两条记录select * from (select dept_id,parent_id,type,name,row_number() over(partition by parent_id,type order by type desc,dept_id) as sort_id from dept) as tmp where tmp.sort_id <3
可以看到每组只显示了两个。
补充:如果在执行上述SQL报错,sql_mode=ONLY_FULL_GROUP_BY那就是不允许非分组的字段出现在select里,只需要查看当前SQL规则select @@sql_mode,将其中的sql_mode=ONLY_FULL_GROUP_BY删除即可。
2. rank
rank 和 row_number的区别就是,对于分组、排序的字段,rank如果是相同的那么sort_id也是相同的,并且相同的sort_id会占用后续的sort_id,举个例子 1,2,2,4 (也就是说相同的sort第二个2占用了3导致sort_id为2之后直接未4,row_number则是不重复的,即使分组和排序字段一样也是递增sort_id。
执行如下SQL:
select dept_id,parent_id,type,name,company_id,rank() over(partition by parent_id,type order by type,company_id) as sort_id from dept
执行结果如下:
3. dense_rank dense_rank 和 rank的区别是 sort_id相同分组、排序也会相同,但是sort_id是连续的,举个例子 1,2,2,3(也就是说重复的sort_id不会占用后续的sort_id。
执行如下SQL:select dept_id,parent_id,type,name,company_id,dense_rank() over(partition by parent_id,type order by type,company_id) as sort_id from dept