点击上方「数据分析师的FIRE人生」→
点击右上角「...」→设为星标⭐

大家好,我是风影楼,一名互联网公司的数据分析师。之前我曾在CSDN编写了Hive系列的付费博客专栏,目前收获了25W次的访问,不过由于CSDN的付费设置无法取消,所以我决定在公众号重新免费分享一遍。这一篇主要介绍Hive中两类功能的开窗函数,分别是组内累计统计函数和组内排序函数。
1、什么是开窗函数
这类函数叫法很多,包括分析函数、窗口函数、开窗函数、分析窗口函数,其实说的都是一类函数。开窗函数用于为行定义一个窗口(这里的窗口是指运算将要操作的行的集合),它对一组值进行操作,不需要使用GROUP BY子句对数据进行分组,能够在同一行中同时返回基础行的列和聚合列。
2、开窗函数语法
开窗函数 over(partition by 列名1,列名2 …… order by 列名3,列名4 …… [desc])
括号中的两个关键词partition by 和order by 可以只出现一个。
partition by 和order by 后面的列名可以根据需求设定任意数量个列名。
order by后面可以选择是否跟desc,加上为倒序排序(从大到小),不加则默认为从小到大排序。
3、组内累计统计函数 sum、avg、min、max
讲解这几个窗口函数前,先创建一个表,以实际例子讲解大家更容易理解。现有表字段如下:第一列是月份,第二列代表商铺名称,第三列代表该商铺该月营业额(万元)。
select * from temp_test9;month shop money2019-01 a 102019-02 a 202019-03 a 302019-01 b 102019-02 b 202019-03 b 30
3.1 累计求和 sum(xx) over
需求1:求商店a每个月从1月累计到该月的总营业额,即:
1月的数据是1月的营业额
2月的数据是1月+2月的营业额
3月的数据是1月+2月+3月的营业额
SELECT month,SUM(MONEY) OVER (ORDER BY month --按照月份进行排序,然后默认从起点行到当前行做累计求和) AS money_leijiFROM temp_test9WHERE shop = 'a'; --开窗函数不用写group by结果:month money_leiji2019-01 10.02019-02 30.02019-03 60.0
需求2:同时求出商店a、b每个月从1月累计到该月的总营业额
SELECT shop,month,SUM(MONEY) OVER (PARTITION BY shop ORDER BY month --先按照shop进行分组,然后每个组内再按照月份进行排序,最后默认从起点行到当前行做累计求和) AS money_leijiFROM temp_test9;结果:shop month money_leijia 2019-01 10.0a 2019-02 30.0a 2019-03 60.0b 2019-01 10.0b 2019-02 30.0b 2019-03 60.0
3.2 累计求平均值 avg(xx) over
其他的开窗函数和求和的累计逻辑都是相同的。
举例:
同时求出商店a、b每个月从1月累计到该月的平均营业额
SELECT shop,month,AVG(MONEY) OVER (PARTITION BY shop ORDER BY month --先按照shop进行分组,然后每个组内再按照月份进行排序,最后默认从起点行到当前行做累计求均值) AS money_leijiFROM temp_test9;结果:shop month money_leijia 2019-01 10.0a 2019-02 15.0a 2019-03 20.0b 2019-01 10.0b 2019-02 15.0b 2019-03 20.0
3.3 累计求最大值 max(xx) over
举例:
同时求出商店a、b每个月从1月累计到该月的营业额最大值
SELECT shop,month,MAX(MONEY) OVER (PARTITION BY shop ORDER BY month --先按照shop进行分组,然后每个组内再按照月份进行排序,最后默认从起点行到当前行做累计求最大值) AS money_leiji_maxFROM temp_test9;结果:shop month money_leiji_maxa 2019-01 10a 2019-02 20a 2019-03 30b 2019-01 10b 2019-02 20b 2019-03 30
3.4 累计求最小值 min(xx) over
举例:
同时求出商店a、b每个月从1月累计到该月的营业额最小值
SELECT shop,month,MIN(MONEY) OVER (PARTITION BY shop ORDER BY month --先按照shop进行分组,然后每个组内再按照月份进行排序,最后默认从起点行到当前行做累计求最小值) AS money_leiji_minFROM temp_test9;结果:shop month money_leiji_mina 2019-01 10a 2019-02 10a 2019-03 10b 2019-01 10b 2019-02 10b 2019-03 10
3.5 自定义累计方式
除了上面常用的累计统计方式之外,Hive还允许自定义累计方式。默认的累计方式是按起点行到当前行做累计,自定义累计方式主要有以下4种:
当前行+往前几行
当前行+往后几行
当前行+往前几行+往后几行
当前行+往后所有行
这几种自定义的累计方式应用场景较少,这里只介绍一下语法:
1)当前行+往前几行
1 PRECEDING指往前1行,这里可以根据需求任意指定数值
OVER (PARTITION BY 列名1 ORDER BY 列名2 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
2)当前行+往后几行
1 FOLLOWING指往后1行,这个值可以根据需求指定任意数值
OVER (PARTITION BY 列名1 ORDER BY 列名2 ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING)
3)当前行+往前几行+往后几行
1 PRECEDING指往前1行,1 FOLLOWING指往后1行,这两个值均可以根据需求指定任意数值
OVER (PARTITION BY 列名1 ORDER BY 列名2 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
4)当前行+往后所有行
OVER (PARTITION BY 列名1 ORDER BY 列名2 ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
4、组内排序函数
4.1 row_number()
row_number()会生成数据项在分组中的排名,排名即便相等也不会有并列排名,相同排名随机排序。
现有数据如下表:select * from temp_test10;month shop money2019-01 a 42019-01 b 32019-01 c 32019-01 d 22019-01 e 12019-02 a 12019-02 b 22019-02 c 32019-02 d 32019-02 e 4
应用场景1:生成排序后的唯一序号
举例:首先按照月份进行分组,然后每个组内按照营业额从大到小排序,为组内每一行数据得到一个唯一序号。
SELECT month,shop,MONEY,row_number() OVER (PARTITION BY month ORDER BY MONEY DESC --按照月份进行分组,然后每个组内按照营业额从大到小排序) AS rk --生成的排序序号FROM temp_test10结果:month shop money rk2019-01 a 4 12019-01 c 3 22019-01 b 3 32019-01 d 2 42019-01 e 1 52019-02 e 4 12019-02 d 3 22019-02 c 3 32019-02 b 2 42019-02 a 1 5
应用场景2:取top n
举例:取出1月和2月每个月营业额排名前3的店铺及营业额。
SELECT *FROM (SELECT month,shop,MONEY,row_number() OVER (PARTITION BY month ORDER BY MONEY DESC --按照月份进行分组,然后每个组内按照营业额从大到小排序) AS rkFROM temp_test10) aWHERE rk <= 3;结果:a.month a.shop a.money a.rk2019-01 a 4 12019-01 c 3 22019-01 b 3 32019-02 e 4 12019-02 d 3 22019-02 c 3 3
应用场景3:每个分组内取出n个随机值
row_number()配合rand()函数即可实现每个分组内取出n个随机值的需求。
举例:每个月随机抽取两家店铺
SELECT *FROM (SELECT month,shop,MONEY,row_number() OVER (PARTITION BY month ORDER BY rand(1) --可以使用任意数作为种子进行随机排序,也可以不填,直接使用rand()) AS rkFROM temp_test10) aWHERE rk <= 2; --限制rk来取出n个随机值结果:a.month a.shop a.money a.rk2019-01 c 3 12019-01 d 2 22019-02 a 1 12019-02 e 4 2
4.2 rank()
rank()可以生成数据项在分组中的排名,排名相等时会产生并列排名,然后会在名次中留下空位。
举例:首先按照月份进行分组,然后每个组内按照营业额从大到小排序,生成排名,并列排名后留下空位。
SELECT month,shop,MONEY,rank() OVER (PARTITION BY month ORDER BY MONEY DESC --按照月份进行分组,然后每个组内按照营业额从大到小排序) AS rk --生成的排序序号FROM temp_test10;结果:month shop money rk2019-01 a 4 12019-01 c 3 22019-01 b 3 22019-01 d 2 42019-01 e 1 52019-02 e 4 12019-02 d 3 22019-02 c 3 22019-02 b 2 42019-02 a 1 5
4.3 dense_rank()
dense_rank()可以生成数据项在分组中的排名,排名相等时会产生并列排名,但不会在名次中留下空位。应用场景也不多,很少需要使用,了解即可。
举例:首先按照月份进行分组,然后每个组内按照营业额从大到小排序,生成排名,并列排名后不要留下空位。
SELECT month,shop,MONEY,dense_rank() OVER (PARTITION BY month ORDER BY MONEY DESC --按照月份进行分组,然后每个组内按照营业额从大到小排序) AS rk --生成的排序序号FROM temp_test10;结果:month shop money rk2019-01 a 4 12019-01 c 3 22019-01 b 3 22019-01 d 2 32019-01 e 1 42019-02 e 4 12019-02 d 3 22019-02 c 3 22019-02 b 2 32019-02 a 1 4
由于公众号平台更改了推送规则,如果不想错过后续内容,记得点下“赞”和“在看”,这样下次有新文章推送,就会第一时间出现在你的订阅号列表里。
·END·

点个在看你最好看





