HIVE中开窗函数的使用

HIVE中开窗函数的使用

相关函数说明 OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化。 CURRENT ROW:当前行 n PRECEDING:往前n行数据 n FOLLOWING:往后n行数据 UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING表示到后面的终点 LAG(col,n,default_val):往前第n行数据 LEAD(col,n, default_val):往后第n行数据 NTILE(n):把**有序分区**中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。注意:n必须为int类型。

表:

+----------------+---------------------+----------------+--+
| business.name  | business.orderdate  | business.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             |
+----------------+---------------------+----------------+--+

1、查询在2017年4月份购买过的顾客及总人数

select distinct name,count(*) over() from business where substring(orderdate,1,7)="2017-04";

+-------+-----------------+--+
| name  | count_window_0  |
+-------+-----------------+--+
| mart  | 2               |
| jack  | 2               |
+-------+-----------------+--+

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

select *,sum(cost) over(partition by substring(orderdate,1,7)) from business;

+----------------+---------------------+----------------+---------------+--+
| business.name  | business.orderdate  | business.cost  | sum_window_0  |
+----------------+---------------------+----------------+---------------+--+
| jack           | 2017-01-01          | 10             | 205           |
| jack           | 2017-01-08          | 55             | 205           |
| tony           | 2017-01-07          | 50             | 205           |
| jack           | 2017-01-05          | 46             | 205           |
| tony           | 2017-01-04          | 29             | 205           |
| tony           | 2017-01-02          | 15             | 205           |
| jack           | 2017-02-03          | 23             | 23            |
| mart           | 2017-04-13          | 94             | 341           |
| jack           | 2017-04-06          | 42             | 341           |
| mart           | 2017-04-11          | 75             | 341           |
| mart           | 2017-04-09          | 68             | 341           |
| mart           | 2017-04-08          | 62             | 341           |
| neil           | 2017-05-10          | 12             | 12            |
| neil           | 2017-06-12          | 80             | 80            |
+----------------+---------------------+----------------+---------------+--+

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

3.1

select *,sum(cost) over(partition by name order by substring(orderdate,1,7)) from business;

+----------------+---------------------+----------------+---------------+--+
| business.name  | business.orderdate  | business.cost  | sum_window_0  |
+----------------+---------------------+----------------+---------------+--+
| jack           | 2017-01-05          | 46             | 111           |
| jack           | 2017-01-08          | 55             | 111           |
| jack           | 2017-01-01          | 10             | 111           |
| jack           | 2017-02-03          | 23             | 134           |
| jack           | 2017-04-06          | 42             | 176           |
| mart           | 2017-04-13          | 94             | 299           |
| mart           | 2017-04-11          | 75             | 299           |
| mart           | 2017-04-09          | 68             | 299           |
| mart           | 2017-04-08          | 62             | 299           |
| neil           | 2017-05-10          | 12             | 12            |
| neil           | 2017-06-12          | 80             | 92            |
| tony           | 2017-01-04          | 29             | 94            |
| tony           | 2017-01-02          | 15             | 94            |
| tony           | 2017-01-07          | 50             | 94            |
+----------------+---------------------+----------------+---------------+--+

3.2

select *,sum(cost) over(order by orderdate rows between unbounded preceding and current row) from business;

+----------------+---------------------+----------------+---------------+--+
| business.name  | business.orderdate  | business.cost  | sum_window_0  |
+----------------+---------------------+----------------+---------------+--+
| jack           | 2017-01-01          | 10             | 10            |
| tony           | 2017-01-02          | 15             | 25            |
| tony           | 2017-01-04          | 29             | 54            |
| jack           | 2017-01-05          | 46             | 100           |
| tony           | 2017-01-07          | 50             | 150           |
| jack           | 2017-01-08          | 55             | 205           |
| jack           | 2017-02-03          | 23             | 228           |
| jack           | 2017-04-06          | 42             | 270           |
| mart           | 2017-04-08          | 62             | 332           |
| mart           | 2017-04-09          | 68             | 400           |
| mart           | 2017-04-11          | 75             | 475           |
| mart           | 2017-04-13          | 94             | 569           |
| neil           | 2017-05-10          | 12             | 581           |
| neil           | 2017-06-12          | 80             | 661           |
+----------------+---------------------+----------------+---------------+--+

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;

+-------+-------------+-------+----------+----------+----------+----------+----------+----------+----------+--+
| name  |  orderdate  | cost  | sample1  | sample2  | sample3  | sample4  | sample5  | sample6  | sample7  |
+-------+-------------+-------+----------+----------+----------+----------+----------+----------+----------+--+
| jack  | 2017-01-01  | 10    | 661      | 176      | 10       | 10       | 10       | 56       | 176      |
| jack  | 2017-01-05  | 46    | 661      | 176      | 56       | 56       | 56       | 111      | 166      |
| jack  | 2017-01-08  | 55    | 661      | 176      | 111      | 111      | 101      | 124      | 120      |
| jack  | 2017-02-03  | 23    | 661      | 176      | 134      | 134      | 78       | 120      | 65       |
| jack  | 2017-04-06  | 42    | 661      | 176      | 176      | 176      | 65       | 65       | 42       |
| mart  | 2017-04-08  | 62    | 661      | 299      | 62       | 62       | 62       | 130      | 299      |
| mart  | 2017-04-09  | 68    | 661      | 299      | 130      | 130      | 130      | 205      | 237      |
| mart  | 2017-04-11  | 75    | 661      | 299      | 205      | 205      | 143      | 237      | 169      |
| mart  | 2017-04-13  | 94    | 661      | 299      | 299      | 299      | 169      | 169      | 94       |
| neil  | 2017-05-10  | 12    | 661      | 92       | 12       | 12       | 12       | 92       | 92       |
| neil  | 2017-06-12  | 80    | 661      | 92       | 92       | 92       | 92       | 92       | 80       |
| tony  | 2017-01-02  | 15    | 661      | 94       | 15       | 15       | 15       | 44       | 94       |
| tony  | 2017-01-04  | 29    | 661      | 94       | 44       | 44       | 44       | 94       | 79       |
| tony  | 2017-01-07  | 50    | 661      | 94       | 94       | 94       | 79       | 79       | 50       |
+-------+-------------+-------+----------+----------+----------+----------+----------+----------+----------+--+

其中sample3和sample4是一样的,都是按name分组,组内数据累加
上面总共开了7个窗口函数,select执行完了之后(select不需要执行MapReduce程序),每多一个窗口,就多一个MapReduce执行函数,但是这个前提是窗口开的不一样,只有窗口开的不一样才有额外的MapReduce,
但是,sample3~sample7的窗口都是一样的,只不过他们各自加的行的范围不一样而已,但是窗口都是一个窗口。

4、查询每个顾客上次的购买时间

4.1

select *,lag(orderdate) over(partition by name order by orderdate) from business;

+----------------+---------------------+----------------+---------------+--+
| business.name  | business.orderdate  | business.cost  | lag_window_0  |
+----------------+---------------------+----------------+---------------+--+
| jack           | 2017-01-01          | 10             | NULL          |
| jack           | 2017-01-05          | 46             | 2017-01-01    |
| jack           | 2017-01-08          | 55             | 2017-01-05    |
| jack           | 2017-02-03          | 23             | 2017-01-08    |
| jack           | 2017-04-06          | 42             | 2017-02-03    |
| mart           | 2017-04-08          | 62             | NULL          |
| mart           | 2017-04-09          | 68             | 2017-04-08    |
| mart           | 2017-04-11          | 75             | 2017-04-09    |
| mart           | 2017-04-13          | 94             | 2017-04-11    |
| neil           | 2017-05-10          | 12             | NULL          |
| neil           | 2017-06-12          | 80             | 2017-05-10    |
| tony           | 2017-01-02          | 15             | NULL          |
| tony           | 2017-01-04          | 29             | 2017-01-02    |
| tony           | 2017-01-07          | 50             | 2017-01-04    |
+----------------+---------------------+----------------+---------------+--+

4.2

select *,lag(orderdate,1,"1970-01-01") over(partition by name order by orderdate) from business;

+----------------+---------------------+----------------+---------------+--+
| business.name  | business.orderdate  | business.cost  | lag_window_0  |
+----------------+---------------------+----------------+---------------+--+
| jack           | 2017-01-01          | 10             | 1970-01-01    |
| jack           | 2017-01-05          | 46             | 2017-01-01    |
| jack           | 2017-01-08          | 55             | 2017-01-05    |
| jack           | 2017-02-03          | 23             | 2017-01-08    |
| jack           | 2017-04-06          | 42             | 2017-02-03    |
| mart           | 2017-04-08          | 62             | 1970-01-01    |
| mart           | 2017-04-09          | 68             | 2017-04-08    |
| mart           | 2017-04-11          | 75             | 2017-04-09    |
| mart           | 2017-04-13          | 94             | 2017-04-11    |
| neil           | 2017-05-10          | 12             | 1970-01-01    |
| neil           | 2017-06-12          | 80             | 2017-05-10    |
| tony           | 2017-01-02          | 15             | 1970-01-01    |
| tony           | 2017-01-04          | 29             | 2017-01-02    |
| tony           | 2017-01-07          | 50             | 2017-01-04    |
+----------------+---------------------+----------------+---------------+--+

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

5.1 先体验一下ntile函数的分组功能

select *,ntile(5) tgroup over(order by orderdate) from business;

+----------------+---------------------+----------------+-----------------+--+
| business.name  | business.orderdate  | business.cost  | ntile_window_0  |
+----------------+---------------------+----------------+-----------------+--+
| jack           | 2017-01-01          | 10             | 1               |
| tony           | 2017-01-02          | 15             | 1               |
| tony           | 2017-01-04          | 29             | 1               |
| jack           | 2017-01-05          | 46             | 2               |
| tony           | 2017-01-07          | 50             | 2               |
| jack           | 2017-01-08          | 55             | 2               |
| jack           | 2017-02-03          | 23             | 3               |
| jack           | 2017-04-06          | 42             | 3               |
| mart           | 2017-04-08          | 62             | 3               |
| mart           | 2017-04-09          | 68             | 4               |
| mart           | 2017-04-11          | 75             | 4               |
| mart           | 2017-04-13          | 94             | 4               |
| neil           | 2017-05-10          | 12             | 5               |
| neil           | 2017-06-12          | 80             | 5               |
+----------------+---------------------+----------------+-----------------+--+

select * from (select *,ntile(5) tgroup over(order by orderdate) from business) t1 where t1.tgroup=1;

5.3 体验一下persent_rank()函数,求大致比例,不过是从0开始的。

select *,percent_rank() over(order by orderdate) pr from business;


+----------------+---------------------+----------------+----------------------+--+
| business.name  | business.orderdate  | business.cost  |          pr          |
+----------------+---------------------+----------------+----------------------+--+
| jack           | 2017-01-01          | 10             | 0.0                  |
| tony           | 2017-01-02          | 15             | 0.07692307692307693  |
| tony           | 2017-01-04          | 29             | 0.15384615384615385  |
| jack           | 2017-01-05          | 46             | 0.23076923076923078  |
| tony           | 2017-01-07          | 50             | 0.3076923076923077   |
| jack           | 2017-01-08          | 55             | 0.38461538461538464  |
| jack           | 2017-02-03          | 23             | 0.46153846153846156  |
| jack           | 2017-04-06          | 42             | 0.5384615384615384   |
| mart           | 2017-04-08          | 62             | 0.6153846153846154   |
| mart           | 2017-04-09          | 68             | 0.6923076923076923   |
| mart           | 2017-04-11          | 75             | 0.7692307692307693   |
| mart           | 2017-04-13          | 94             | 0.8461538461538461   |
| neil           | 2017-05-10          | 12             | 0.9230769230769231   |
| neil           | 2017-06-12          | 80             | 1.0                  |
+----------------+---------------------+----------------+----------------------+--+

给定下表:

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

体验rank()函数

select *,rank() over(partition by subject order by score desc) r from score;


+-------------+----------------+--------------+----+--+
| score.name  | score.subject  | score.score  | r  |
+-------------+----------------+--------------+----+--+
| 孙悟空         | 数学             | 95           | 1  |
| 宋宋          | 数学             | 86           | 2  |
| 婷婷          | 数学             | 85           | 3  |
| 大海          | 数学             | 56           | 4  |
| 宋宋          | 英语             | 84           | 1  |
| 大海          | 英语             | 84           | 1  |
| 婷婷          | 英语             | 78           | 3  |
| 孙悟空         | 英语             | 68           | 4  |
| 大海          | 语文             | 94           | 1  |
| 孙悟空         | 语文             | 87           | 2  |
| 婷婷          | 语文             | 65           | 3  |
| 宋宋          | 语文             | 64           | 4  |
+-------------+----------------+--------------+----+--+

对比rank()、dense_rank()、row_number()差异

select *,rank() over(partition by subject order by score desc) r, 
dense_rank() over(partition by subject order by score desc) dr,
row_number() over(partition by subject order by score desc) rr
from score;

+-------------+----------------+--------------+----+-----+-----+--+
| score.name  | score.subject  | score.score  | r  | dr  | rr  |
+-------------+----------------+--------------+----+-----+-----+--+
| 孙悟空         | 数学             | 95           | 1  | 1   | 1   |
| 宋宋          | 数学             | 86           | 2  | 2   | 2   |
| 婷婷          | 数学             | 85           | 3  | 3   | 3   |
| 大海          | 数学             | 56           | 4  | 4   | 4   |
| 宋宋          | 英语             | 84           | 1  | 1   | 1   |
| 大海          | 英语             | 84           | 1  | 1   | 2   |
| 婷婷          | 英语             | 78           | 3  | 2   | 3   |
| 孙悟空         | 英语             | 68           | 4  | 3   | 4   |
| 大海          | 语文             | 94           | 1  | 1   | 1   |
| 孙悟空         | 语文             | 87           | 2  | 2   | 2   |
| 婷婷          | 语文             | 65           | 3  | 3   | 3   |
| 宋宋          | 语文             | 64           | 4  | 4   | 4   |
+-------------+----------------+--------------+----+-----+-----+--+

posted @ 2019-11-24 23:50  craz_cat  阅读(2284)  评论(1)    收藏  举报