Mysql8之窗口函数

目录

前言

数据准备

实例:

聚合函数+over()

partition by,order by

sum() 叠加求和性

window子句

排序问题

ntile 数据分割

lag,lead

first_value和last_value


前言

文章内容是关于Mysql8的窗口函数的使用,内容会结合我做到的相关题目或者结合相关业务的分析
来进行写作,可能并不全但后续会进行补充.


数据准备

以一张购物表为例

create table if not exists shop(name varchar(20),buy_date date,cost int);
Truncate table shop;
insert into shop (name,buy_date, cost) values ('nanxi', '2023-02-05', '40');
insert into shop (name,buy_date, cost) values ('jack ', '2022-04-06', '15');
insert into shop (name,buy_date, cost) values ('bome ', '2023-08-04', '70');
insert into shop (name,buy_date, cost) values ('xixi ', '2023-06-07', '66');
insert into shop (name,buy_date, cost) values ('jack ', '2021-02-04', '80');
insert into shop (name,buy_date, cost) values ('bome ', '2022-07-15', '10');
insert into shop (name,buy_date, cost) values ('bolle', '2021-06-25', '130');
insert into shop (name,buy_date, cost) values ('fufu ', '2022-02-21', '70');
insert into shop (name,buy_date, cost) values ('nanxi', '2023-11-16', '89');
insert into shop (name,buy_date, cost) values ('bolle', '2022-07-04', '80');

实例:

聚合函数+over()

首先注意窗口函数的执行是只位于order by 之前的

如果我们使用正常的方法对购物表去统计每个人有几条记录,并输出3列信息再加一列统计信息,此时对于多次出现的人,我们是需要使用gorup by子句去分组统计name列,但是同时我们又想要输出全部行呢,使用group by会使得name相同的变成一组,最终输出一行,并且只能输出

name列和统计列,想要输出表中jack的购物信息,就没有办法

但是如果我们使用窗口函数就不同了

 可以看到使用了窗口函数 count(1) over() 之后

多了一列,但是很明显这一列统计的是全部人的个数,但是它已经可以每行显示了,还记得标题吗,窗口函数,窗口指的是什么呢,当我们使用  聚合函数 over() 这个格式时,默认窗口就一个,就是整个表,所以我们想要每个人的话还是需要进行分组,但是我们可以在窗口函数里分组

partition by,order by

 可以看到我们在over()里加入了partition by 和order by子句,首先partition by 类似于group

by子句,但是partition by 在窗口函数里的作用的进行分窗口的,partition by name就是按照姓名进行分窗口,可以看到表按name分成了6个窗口,而order by子句是对每个窗口进行排序

sum() 叠加求和性

对于聚合函数 sum() over(order by...) 一旦由窗口进行了order by 之后会产生如下效果

可以看到按照name分成多个窗口,每个窗口对cost列进行求和,cnt列不再是相同的了,而是按照cost列叠加逐渐相加 

window子句

window子句: 
PRECEDIN:           往前 
FOLLOWING:      往后 
CURRENT ROW:当前行 
UNBOUNDED :   起点,

UNBOUNDED PRECEDING 表示从前面的起点,

UNBOUNDED FOLLOWING:表示到后面的终点
例:
select name,buy_date,cost,
sum(cost) over() as sample1,--所有行相加
sum(cost) over(partition by name) as sample2,--按name分组,组内数据相加
sum(cost) over(partition by name order buy_date) as sample3,--按name分组,组内数据累加
sum(cost) over(partition by name order by buy_date rows between UNBOUNDED PRECEDING and current row )  as sample4 ,--和sample3一样,由起点到当前行的聚合
sum(cost) over(partition by name order by buy_date rows between 1 PRECEDING   and current row) as sample5, --当前行和前面一行做聚合
sum(cost) over(partition by name order by buy_datee rows between 1 PRECEDING   AND 1 FOLLOWING  ) as sample6,--当前行和前边一行及后面一行
sum(cost) over(partition by name order by buy_date rows between current row and UNBOUNDED FOLLOWING ) as sample7 --当前行及后面所有行
from shop;

注意:

意思是 本行和前面的两行进行求和

sum(salary) over(partition by id order by month rows between 2 PRECEDING   and current row)

意思也是 本行和前面的两行进行求和

sum(salary) over(partition by id order by month range  2 preceding) Salary

但是 range 和row 并不相同 row就是物理上的两行

比如这两个案例,都是通过id分组按照月份进行排序,如果月份是按顺序的那这两个结果一样

但是如果月份并不连续例如

month Salary

1        100

3        200

5        300

7        200

此时如果在读取month=5这一行 那么rows 统计的就是1,3,5三行也就是600

但如果是range,range会按照逻辑进行统计,统计的就是3,4,5三个月,4月没有就是0结果是500

排序问题

row_number(),rank(),dense_rank()

这三个窗口在进行数据分析时经常使用

 row_number()从1开始,按照顺序,生成分组内记录的序列,row_number()的值不会存在重复,当排序的值相同时,按照表中记录的顺序进行排列 

1,2,3,4,5....
RANK() 生成数据项在分组中的排名,排名相等会在名次中留下空位 

1,2,2,4,5
DENSE_RANK() 生成数据项在分组中的排名,排名相等会在名次中不会留下空位

1,2,2,3,4,5....

注意

 在使用排名函数的时候需要注意以下三点:

  1、排名函数必须有 OVER 子句。

  2、排名函数必须有包含 ORDER BY 的 OVER 子句。

  3、分组内从1开始排序。

例:

 #注意对于row_number,对于相同的数据会按照表中原来的数据进行排序

   这时要注意如果 row_number() over(order by cost desc)这样逆序排序,同时还有一列是

   row_number() over(order by cost) 这样结果表就是按cost正序的,谁是最后进行的order by

   就是按照谁的顺序,但是此时问题也出现了,虽然顺序是按最后的排序了,但是之前的排序如      果有相同数据就会出现乱序

 可以看到70,80两对,顺序就是按照原来的顺序,并没有逆序

  

 此时按照多列进行排序解决整个问题

对于一次正序,一次逆序,多用于求中位数的情况
当行为偶数时两列相差1为中位数,奇数时相等的为中位数

注意对于排序返回值是BIGINT是无符号的,所以不可以直接相减

相减要使用强制转换,换成范围更大的DECIMAL

abs( CAST(rk1 AS DECIMAL) - CAST(rk2 AS DECIMAL))=1

ntile 数据分割

ntile(n),用于将分组数据按照顺序切分成n片,返回当前切片值

比如我们想要返回日期前1/2的消费

 选取rk为1的就是前1/2

lag,lead

取值最近的数据问题lag() over()
lag(参数1,参数2,参数3) 往上
参数1:列
参数2:错位值
参数3:null值使用参数3代替

rk列就是组内当前buydate的上一行数据,如果没有就是null
lead 往下

 

first_value和last_value

#first_value取分组内排序后,截止到当前行,第一个值 


#last_value取分组内排序后,截止到当前行,最后一个值

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星星妳睡了吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值