Hive之窗口函数(一文搞懂)

 

窗口函数简单说就是在执行聚合函数时指定一个操作窗口。窗口函数执行顺序基本靠后,在全局排序order by和limit之前执行

1.相关函数说明

OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化。

重点解释下OVER()函数,OVER()函数中包括三个函数:

包括分区partition by 列名、排序order by 列名、指定窗口范围rows between开始位置and结束位置。我们在使用over()窗口函数时,over()函数中的这三个函数可组合使用也可以不使用。

over()函数中如果不使用这三个函数,窗口大小是针对查询产生的所有数据,如果指定了分区,窗口大小是针对每个分区的数据。

1)、partition by 可理解为group by分组。over(partition by 列名)搭配分析函数时,分析函数按照每一组每一组的数据进行计算的。

2)、rows between开始位置 and 结束位置

是指定窗口范围,比如第一行到当前行。而这个范围是随着数据变化的。over(rows between 开始位置 and 结束位置)搭配分析函数时,分析函数按照这个范围进行计算的

窗口范围说明:
我们常使用的窗口范围是ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(表示从起点到当前行),常用该窗口来计算累加。


PRECEDING:往前
FOLLOWING:往后
CURRENT ROW:当前行
UNBOUNDED:起点(一般结合PRECEDING,FOLLOWING使用)
UNBOUNDED PRECEDING 表示该窗口最前面的行(起点)
UNBOUNDED FOLLOWING:表示该窗口最后面的行(终点)
LAG(col,n,default_val):往前第n行数据,没有数据的话用default_val代替
LEAD(col,n, default_val):往后第n行数据,没有数据的话用default_val代替
NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。注意:n必须为int类型。

比如说:
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(表示从窗口起点到当前行)
ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING(表示往前2行到往后1行)
ROWS BETWEEN 2 PRECEDING AND 1 CURRENT ROW(表示往前2行到当前行)
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING(表示当前行到终点)

2.数据准备:name,orderdate,cost

jack,2017-01-01,10
tony,2017-01-02,15
jack,2017-02-03,23
tony,2017-01-04,29
jack,2017-01-05,46
jack,2017-04-06,42
tony,2017-01-07,50
jack,2017-01-08,55
mart,2017-04-08,62
mart,2017-04-09,68
neil,2017-05-10,12
mart,2017-04-11,75
neil,2017-06-12,80
mart,2017-04-13,94

3.需求

  1. 查询在2017年4月份购买过的顾客及总人数
  2. 查询顾客的购买明细及月购买总额
  3. 上述的场景, 将每个顾客的cost按照日期进行累加
  4. 查询每个顾客上次的购买时间
  5. 查询前20%时间的订单信息

4.创建本地business.txt,导入数据

[hadoop@hadoop100 datas]$ vi business.txt

5.创建hive表并导入数据

create table business(

name string,

orderdate string,

cost int

) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

load data local inpath "/opt/module/datas/business.txt" into table business;

6.按需求查询数据

1)、查询在2017年4月份购买过的顾客及总人数, over() 默认为查询全部的窗口。

select name,count(*) over ()

from business 

where substring(orderdate,1,7) = '2017-04'

group by name;

2)、查询顾客的购买明细及月购买总额

select name,orderdate,cost,sum(cost) over(partition by month(orderdate)) from

 business;

-- 按顾客和月份分组

select name,orderdate,cost,sum(cost) over(partition by name,month(orderdate)) from

 business;

3)上述的场景, 将每个顾客的cost按照日期进行累加

select name,orderdate,cost,

sum(cost) over() as sample1,--所有行相加

sum(cost) over(partition by name) as sample2,--按name分组,组内数据相加

sum(cost) over(partition by name order by orderdate) as sample3,--按name分组,组内数据累加

sum(cost) over(partition by name order by orderdate rows between UNBOUNDED PRECEDING and current row ) as sample4 ,--和sample3一样,由起点到当前行的聚合

sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING and current row) as sample5, --当前行和前面一行做聚合

sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING AND 1 FOLLOWING ) as sample6,--当前行和前边一行及后面一行

sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 --当前行及后面所有行

from business;

rows必须跟在Order by 子句之后,对排序的结果进行限制,使用固定的行数来限制分区中的数据行数量

4)查看顾客上次的购买时间

select name,orderdate,cost,

lag(orderdate,1,'1900-01-01') over(partition by name order by orderdate ) as time1,

lag(orderdate,2) over (partition by name order by orderdate) as time2

from business;

5)查询前20%时间的订单信息

select * from (

    select name,orderdate,cost, ntile(5) over(order by orderdate) sorted

    from business

) t

where sorted = 1;

窗口函数在sql运行的最后才执行,所以需要用自查询的方式进行条件过滤。

7.Rank函数

RANK() 排序相同时会重复,总数不会变 1、1、 3、4

DENSE_RANK() 排序相同时会重复,总数会减少 1、1、 2、3

ROW_NUMBER() 会根据顺序计算1、2、3、4

1、需求

1、每门学科学生成绩排名(是否并列排名、空位排名三种实现)
2、每门学科成绩排名top n的学生

2、原始数据(学生成绩信息)

name    subject score
孙悟空 语文  87
孙悟空 数学  95
孙悟空 英语  68
大海  语文  94
大海  数学  56
大海  英语  84
宋宋  语文  64
宋宋  数学  86
宋宋  英语  84
婷婷  语文  65
婷婷  数学  85
婷婷  英语  78

3、建表并加载数据

create table score
(
name string,
subject string,
score int
) row format delimited fields terminated by "\t";

#加载数据
load data local inpath '/home/hadoop000/data/hive/score.txt' into table score;

4、每门学科学生成绩排名(是否并列排名、空位排名三种实现)

select  *,
rank()over(partition by subject order by score desc) as rank,
row_number()over(partition by subject order by score desc) as row_number,
dense_rank()over(partition by subject order by score desc) as dense_rank
from score

5、每门学科成绩排名top n的学生

select
*
from
(
select
*,
row_number() over(partition by subject order by score desc) rmp
from score
) t
where t.rmp<=3;

 8.lag/lead() over()

LAG(col,n,DEFAULT) 用于统计窗口内往上第n行值

第一个参数为列名,第二个参数为往上第n行(默认为1),第三个参数为默认值(当往上第n行为NULL时候,取默认值,如不指定,则为NULL) 

LEAD(col,n,DEFAULT) 用于统计窗口内往下第n行值

第一个参数为列名,第二个参数为往下第n行(默认为1),第三个参数为默认值(当往下第n行为NULL时候,取默认值,如不指定,则为NULL)

1、数据准备

create table t_hosp(
 user_name string
,age int
,in_hosp date
,out_hosp date)
row format delimited fields terminated by ',';
 
xiaohong,25,2020-05-12,2020-06-03
xiaoming,30,2020-06-06,2020-06-15
xiaohong,25,2020-06-14,2020-06-19
xiaoming,30,2020-06-20,2020-07-02

2、需求:求同一个患者每次住院与上一次出院的时间间隔

step1:

select
user_name
,age
,in_hosp
,out_hosp
,LAG(out_hosp,1,in_hosp) OVER(PARTITION BY user_name ORDER BY out_hosp asc) AS pre_out_date
from
t_hosp
;
其中,LAG(out_hosp,1,in_hosp) OVER(PARTITION BY user_name ORDER BY out_hosp asc)
表示根据user_name分组按照out_hosp升序取每条数据的上一条数据的out_hosp,
如果上一条数据为空,则使用默认值in_hosp来代替

step2:每条数据的in_hosp与pre_out_date的差值即本次住院日期与上次出院日期的间隔

select
user_name,age,in_hosp,out_hosp,
LAG(out_hosp,1,in_hosp) OVER(PARTITION BY user_name ORDER BY out_hosp asc) AS pre_out_date,
datediff(in_hosp,LAG(out_hosp,1,in_hosp) OVER(PARTITION BY user_name ORDER BY out_hosp asc)) as days
from
t_hosp;

 补充:通过执行show functions;命令查询hive的内置函数还有详细的用法

  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

For_dongyang

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

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

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

打赏作者

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

抵扣说明:

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

余额充值