窗口函数
1、hive窗口函数语法
hive中的窗口函数over() ,over()窗口函数的语法结构
分析函数 over(partition by 列名 order by 列名 rows between 开始位置 and 结束位置)
over()函数中包括三个函数:包括分区partition by 列名、排序order by 列名、指定窗口范围rows between 开始位置 and 结束位置。我们在使用over()窗口函数时,over()函数中的这三个函数可组合使用也可以不使用。
over()函数中如果不使用这三个函数,窗口大小是针对查询产生的所有数据,如果指定了分区,窗口大小是针对每个分区的数据。
over()函数中的三个函数讲解
order by
order by是排序的意思,是该窗口中的.
partition by
partition by可理解为group by 分组。over(partition by 列名)搭配分析函数时,分析函数按照每一组每一组的数据进行计算的。
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:表示该窗口最后面的行(终点)
比如说:
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 常与over()一起使用的分析函数:
2.1、聚合类
avg()、sum()、max()、min()
2.2、排名类
row_number()按照值排序时产生一个自增编号,不会重复(如:1、2、3、4、5、6)
rank() 按照值排序时产生一个自增编号,值相等时会重复,会产生空位(如:1、2、3、3、3、6)
dense_rank() 按照值排序时产生一个自增编号,值相等时会重复,不会产生空位(如:1、2、3、3、3、4)
2.3、其他类
lag(列名,往前的行数,[行数为null时的默认值,不指定为null]),可以计算用户上次购买时间,或者用户下次购买时间。
lead(列名,往后的行数,[行数为null时的默认值,不指定为null])
ntile(n) 把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,ntile返回此行所属的组的编号
代码
案例一:
1、使用 over() 函数进行数据统计, 统计每个用户信息及表中数据的总条数
2、求用户明细并统计每天的用户总数
3、计算从第一天到现在的所有 score 大于80分的用户总数
日期 用户ID 分数
logday uid score
字段说明:
数据:
20201210,10001,84 20201210,10002,83 20201210,10003,86 20201211,10001,87 20201211,10002,65 20201211,10003,98 20201212,10001,67 20201212,10002,28 20201212,10003,89 20201213,10001,99 20201213,10002,55 20201213,10003,57
建表并导入数据:
create table test_window (day string, uid string, score int) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
#加载数据
load data local inpath '/export/data/hive/test_window.txt' into table test_window;
1、使用 over() 函数进行数据统计, 统计每个用户信息及表中数据的总条数
select *, count(uid) over() as total from test_window;
2、求用户明细并统计每天的用户总数
select *,count(*) over(partition by logday)as day_total from test_window;
3、计算从第一天到现在的所有 score 大于80分的用户总数
select *,count(*) over(order by logday rows between unbounded preceding and current row)as total from test_window where score > 80;
案例二:
1、查询在2020年4月份购买过的顾客及总人数
2、查询顾客的购买明细及月购买总额
3、查询顾客的购买明细及到目前为止每个顾客购买总金额
4、查询顾客上次的购买时间
5、查询前20%时间的订单信息
字段说明:
用户名 订单日期 订单金额
name orderdate cost
数据:
jack,2020-01-01,11 tony,2020-01-02,16 jack,2020-02-03,22 tony,2020-01-04,28 jack,2020-01-05,47 jack,2020-04-06,43 tony,2020-01-07,50 jack,2020-01-08,55 mart,2020-04-08,63 mart,2020-04-09,69 tom,2020-05-10,13 mart,2020-04-11,76 tom,2020-06-12,81 mart,2020-04-13,95
建表并导入数据:
create table business ( name string, orderdate string, cost int )ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
#加载数据
load data local inpath "/export/data/hive/business.txt" into table business;
1、查询在2020年4月份购买过的顾客及总人数
select *,count(*) over() as total from business where substr(orderdate,1,7) = '2020-04';
2、查询顾客的购买明细及月购买总额
select *,sum(cost) over(partition by name,substr(orderdate,1,7)) total_amount from business;
3、查询顾客的购买明细及到目前为止每个顾客购买总金额
select *,sum(cost) over(partition by name order by orderdate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) total_amount from business;
4、查询顾客上次的购买时间
select name,orderdate,cost,lag(orderdate,1) over(partition by name order by orderdate) last_date from business;
5、查询前20%时间的订单信息
select * from (select *, ntile(5)over(order by orderdate) group_num from business) t where t. group_num = 1;
案例三:
1、每门学科学生成绩排名(是否并列排名、空位排名三种实现)
2、每门学科成绩排名top 3的学生
字段说明:
姓名 科目 成绩
name subject score
数据:
建胜 语文 87 建胜 数学 95 建胜 英语 68 班长 语文 94 班长 数学 56 班长 英语 84 副班长 语文 64 副班长 数学 86 副班长 英语 84 团支书 语文 65 团支书 数学 85 团支书 英语 78
建表导入数据:
create table score ( name string, subject string, score int ) row format delimited fields terminated by "\t";
加载数据
load data local inpath '/export/data/hive/window_score.txt' into table window_score;
1、每门学科学生成绩排名(是否并列排名、空位排名三种实现)
select *, row_number()over(partition by subject order by score desc) as rn, rank()over(partition by subject order by score desc) as rk, dense_rank()over(partition by subject order by score desc) as dr from window_score;
2、每门学科成绩排名top 3的学生
select * from ( select *, row_number() over(partition by subject order by score desc) rmp from window_score ) t where t.rmp<=3;