一、窗口函数是什么

二、窗口函数分类

一、累计计算窗口函数

1、sum() over()

在工作中经常遇到计算截止某月的累计数值,此时需要用sum()开窗

比如给一张交易表user_trade:

hive sum类型 hive中的sum函数_hive sum类型


现在需要计算出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;

hive sum类型 hive中的sum函数_字段_02


现在需要计算出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;

hive sum类型 hive中的sum函数_hive_03


注意:

1、partition by : 起到了分组的作用

2、order by:按照什么顺序进行累加,升序ASC,降序DESC,默认升序

2、avg() over()

现在需要计算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;

hive sum类型 hive中的sum函数_窗口函数_04

3、语法总结

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;

hive sum类型 hive中的sum函数_hive_05


例:选出2019年支付金额排名在第10、20、30名的用户

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);

hive sum类型 hive中的sum函数_窗口函数_06

三、分组排序窗口函数

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;

hive sum类型 hive中的sum函数_hive_07


例:选出2019年退款金额排名前10%的用户

hive sum类型 hive中的sum函数_hive sum类型_08

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;

hive sum类型 hive中的sum函数_hive sum类型_09

四、偏移分析窗口函数

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');

hive sum类型 hive中的sum函数_hive sum类型_10

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');

hive sum类型 hive中的sum函数_数据_11


例:支付时间间隔超过100天的用户数

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;

三、练习