在工作中经常遇到计算截止某月的累计数值,此时需要用sum()开窗
比如给一张交易表user_trade:
现在需要计算出2018年每月的支付总额和当年累计支付总额:
select
a.month,
a.pay_amount,
sum(pay_amount) over(order by month) pay_amount
from(
select
month(dt) month,
sum(pay_amount) pay_amount
from
user_trade
where year(dt)=2018
group by month(dt)
) a;
现在需要计算出2017-2018年每月的支付总额和当年累积支付总额:
select
a.year,
a.month,
a.pay_amount,
sum(a.pay_amount) over(partition by a.year order by a.month)
from
(
select
year(dt) year,
month(dt) month,
sum(pay_amount) pay_amount
from
user_trade
where year(dt) in (2017,2018)
group by year(dt),month(dt)
)a;
注意:
1、partition by : 起到了分组的作用
2、order by:按照什么顺序进行累加,升序ASC,降序DESC,默认升序
现在需要计算2018年每个月的近3个月的平均支付金额:
select
a.month,
a.pay_amount,
avg(a.pay_amount) over(order by a.month rows between 2 preceding and current row)
from
(select
month(dt) month,
sum(pay_amount) pay_amount
from
user_trade
where year(dt)=2018
group by month(dt)
)a;
sum(…A…) over(partition by …B… order by …C… rows between …D1… and …D2…)
avg(…A…) over(partition by …B… order by …C… rows between …D1… and …D2…)
A:需要被加工的字段名称
B:分组的字段名称
C:排序的字段名称
D:计算的行数范围
rows between unbounded preceding and current row :代表包括本行和之前所有的行
rows between current row and unbounded following :包括本行和之后所有的行
rows between 3 preceding and current row : 包括本行以内和前三行
rows between 3 preceding and 1 following:从前三行到下一行(一共5行)
分区排序窗口函数有三个,分别是:
1、row_number() over(partition by A order by B)
2、rank() over(partition by A order by B)
3、dense_rank() over(partition by A order by B)
其中A代表分区的字段名称,B代表排序的字段名称
三者区别:
row_number:它会为查询出来的每一行记录生成一个序号,依次排序且不会重复
rank:排序后的记录值相同的都标记相同的序号,临近的不相同的记录值按之前相同的记录值的个数加1,就是rank排序之后的序号是不连续的
dense_rank:排序后的记录值相同的都标记相同的序号,临近不相同的记录值也按照之前的序号加1,也就是这个排序后的序号总是连续的
例:现在需要计算2019年1月,用户购买的商品品类数量的排名
select
user_name,
count(distinct goods_category),
row_number() over(order by count(distinct goods_category)),
rank() over(order by count(distinct goods_category)),
dense_rank() over(order by count(distinct goods_category))
from
user_trade
where substr(dt,1,7)='2019-01'
group by user_name;
select
a.user_name,
a.pay_amount,
a.rank
from
(
select
user_name,
sum(pay_amount) pay_amount,
rank() over(order by sum(pay_amount) desc) rank
from
user_trade
where year(dt)=2019
group user_name
)a where a.rank in (10,20,30);
ntile(n) over(partition by …A… order by …B…)
n:切分的片数
A:分组的字段名称
B:排序的字段名称
注意:
1、ntile(n):用于将分组数据按照顺序分成n片,返回当前切片值
2、ntile不支持rows between
3、如果切片不均匀,默认增加第一个分片的分布
例:将2019年1月的支付用户,按照支付金额分成5组
select
user_name,
sum(pay_amount) pay_amount,
ntile(5) over(order by sum(pay_amount) desc) level
from
user_trade
where substr(dt,1,7)='2019-01'
group by user_name;
select
a.user_name,
a.refund_amount,
a.level
from
(
select
user_name,
sum(refund_amount) refund_amount,
ntile(10) over(order by sum(refund_amount) desc) level
from
user_refund
where year(dt)=2019
group by user_name
)a
where a.level=1;
1、lag(…) over(…)
2、lead(…) over(…)
Lag和Lead分析函数可以在同一次查询中取出同一字段的前N行的数据(Lag)和后N行的数据(Lead)作为独立的列。
在实际应用当中,若要用到取今天和昨天的某字段差值时,Lag和Lead函数的应用就显得尤为重要。
lag(exp_str,offset,defval) over(partiton by … order by …)
lead(exp_str,offset,defval) over(partition by … order by …)
1、exp_str是字段名称
2、offset是偏移量。当使用lag时,假设当前行在表中排在第5行,而offset为3,则表示我们所要找的数据行就是表中的第2行(即5-3=2)。默认值为1。
3、defval是默认值。当两个函数取上N或下N个值时,当在表中从当前行向前数N行已经超出了表的范围时,就defval作为函数的返回值,若没有指定返回值,则返回NULL。
例如:用户Alice和Alexander的各种时间偏移
1、lag()
select
user_name,
dt,
lag(dt,1,dt) over(partition by user_name order by dt),
lag(dt) over(partition by user_name order by dt),
lag(dt,2,dt) over(partition by user_name order by dt),
lag(dt,2) over(partition by user_name order by dt)
from
user_trade
where dt>'0' and user_name in ('Alice','Alexander');
2、lead()
select
user_name,
dt,
lead(dt,1,dt) over(partition by user_name order by dt),
lead(dt) over(partition by user_name order by dt),
lead(dt,2,dt) over(partition by user_name order by dt),
lead(dt,2) over(partition by user_name order by dt)
from
user_trade
where dt>'0' and user_name in ('Alice','Alexander');
select
count(distinct user_name)
from
(
select
user_name,
dt,
lead(dt) over(partition by user_name order by dt) lead_dt
from
user_trade
where dt>'0'
)a
where a.lead_dt is not null
and datediff(a.lead_dt,a.dt)>100;
上述部分数据及sql参考自开课吧视频,视频链接丢失
Hive 窗口函数