Hive SQL 窗口函数

本文首发:大数据每日哔哔-Hive SQL 窗口函数

Hive 的窗口函数

在 SQL 中有一类函数叫做聚合函数,例如 sum()、avg()、max()、min() 等等,这类函数可以将多行数据按照规则聚集为一行,一般来讲聚集后的行数是要少于聚集前的行数的。但是,有时候我们既要显示聚集前的数据,又要显示聚集后的数据,此时我们便引入了窗口函数。窗口函数主要用于 OLAP 数据分析。

在深入研究Over字句之前,一定要注意:在SQL处理中,窗口函数都是最后一步执行,而且仅位于Order by子句之前。

窗口函数 描述
LAG() LAG()窗口函数返回分区中当前行之前行(可以指定第几行)的值。 如果没有行,则返回null。
LEAD() LEAD()窗口函数返回分区中当前行后面行(可以指定第几行)的值。 如果没有行,则返回null。
FIRST_VALUE FIRST_VALUE窗口函数返回相对于窗口中第一行的指定列的值。
LAST_VALUE LAST_VALUE窗口函数返回相对于窗口中最后一行的指定列的值。

LAG 和 LEAD 的用法:

LAG | LEAD
( <col>, <line_num>, <DEFAULT> )
OVER ( [ PARTITION BY ] [ ORDER BY ] )

FIRST_VALUE 和 LAST_VALUE 的用法:

FIRST_VALUE | LAST_VALUE
( <col>,<ignore nulls as boolean> ) OVER
( [ PARTITION BY ] [ ORDER BY ][ window_clause ] )

下面举个例子,数据集如下:

hive> select * from tmp_pv;
OK
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2019-02-10  1
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2019-02-11  5
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2019-02-12  7
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2019-02-13  3
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2019-02-14  2
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2019-02-15  4
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2019-02-16  4
993BD7AD-3B62-BA0C-15AE-A14B85921889    2019-02-10  2
993BD7AD-3B62-BA0C-15AE-A14B85921889    2019-02-11  9
993BD7AD-3B62-BA0C-15AE-A14B85921889    2019-02-12  3
993BD7AD-3B62-BA0C-15AE-A14B85921889    2019-02-13  10
993BD7AD-3B62-BA0C-15AE-A14B85921889    2019-02-14  1
993BD7AD-3B62-BA0C-15AE-A14B85921889    2019-02-15  8
993BD7AD-3B62-BA0C-15AE-A14B85921889    2019-02-16  2
Time taken: 0.102 seconds, Fetched: 14 row(s)

<a name="Y1tyI"></a>

LAG(col,n,default)

与 partitioned by 结合使用,返回当前分区中,当前行之前的第 n 行对应的值。如果没有则默认换回 null。第一个参数为列名,第二个参数为当前行之前第n行(可选,默认为1),第三个参数为缺失时默认值(当前行之前第n行为NULL没有时,返回该默认值,如不指定,则为NULL)。

为了比较每个用户浏览次数与前一天的浏览次数进行比较,查询返回当前浏览次数以及前一天的浏览数量。由于在2019-02-10之前没有浏览行为,前一天的浏览次数设置为0(不设置默认为NULL)。

hive> select gid, dt, pv, lag(pv, 1, 0) over (partition by gid order by dt) as pre_pv from tmp_pv;
 
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-10  1   0
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-11  5   1
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-12  7   5
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-13  3   7
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-14  2   3
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-15  4   2
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-16  4   4
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-10  2   0
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-11  9   2
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-12  3   9
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-13  10  3
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-14  1   10
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-15  8   1
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-16  2   8
Time taken: 11.783 seconds, Fetched: 14 row(s)

<a name="V4ogf"></a>

LEAD(col,n,default)

与 LAG 函数相反。

<a name="CA4fi"></a>

FIRST_VALUE(col,布尔值)

第一个参数是需要第一个值的列,第二个(可选)参数必须是默认为false的布尔值。如果设置为true,则跳过空值。

hive> select gid,dt,pv,first_value(pv,true) over(partition by gid order by dt) as first_value from temp_pv; 
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-10  1   1
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-11  5   1
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-12  7   1
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-13  3   1
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-14  2   1
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-15  4   1
0006D2BC-4DF9-4C0B-83AD-0183789E78D4    2017-02-16  4   1
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-10  2   2
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-11  9   2
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-12  3   2
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-13  10  2
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-14  1   2
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-15  8   2
993BD7AD-3B62-BA0C-15AE-A14B85921889    2017-02-16  2   2
Time taken: 9.862 seconds, Fetched: 14 row(s)

<a name="2f562"></a>

LAST_VALUE(col,布尔值)

与 FIRST_VALUE() 函数相反,这里就不进行演示了。

<a name="cDqav"></a>

over子句

官方 OVER子句 包括几个部分:

  • 聚合函数(count, sum, min, max, avg)
  • OVER 子句
  • PARTITION BY 子句
  • ORDER BY 子句
  • WINDOW 子句

结合具体的业务场景,SQL 语句如下:<br />

---1)201504月份的销售额
select sum(amount) as total_amt
from order_window 
where substr(order_date,1,7)='2015-04'
;
---2)201504月份的订单明细与销售额
select user_name, order_date, amount
      ,sum(amount) over() as total_amt
from order_window
where substr(order_date,1,7)='2015-04'
;
---3)客户的订单明细与月购买金额
select user_name, order_date, amount
      ,sum(amount) over (partition by month(order_date)) month_amt
from order_window
;
---4)客户的订单明细与累计购买金额
select user_name, order_date, amount
      ,sum(amount) over (partition by month(order_date) order by order_date) month_add_amt
from order_window
;
---5)不同窗口的销售额
select 
     user_name
    ,order_date
    ,amount
    ,sum(amount) over() as sample1 --所有行相加
    ,sum(amount) over(partition by user_name) as sample2 --按name分组,组内数据相加
    ,sum(amount) over(partition by user_name order by order_date) as sample3 --按name分组,组内数据累加
    ,sum(amount) over(partition by user_name order by order_date rows between UNBOUNDED PRECEDING and current row) as sample4 --和sample3一样,由起点到当前行的聚合
    ,sum(amount) over(partition by user_name order by order_date rows between 1 PRECEDING and current row) as sample5 --当前行和前面一行做聚合
    ,sum(amount) over(partition by user_name order by order_date rows between 1 PRECEDING and 1 FOLLOWING) as sample6 --当前行和前边一行及后面一行
    ,sum(amount) over(partition by user_name order by order_date rows between current row and UNBOUNDED FOLLOWING) as sample7 --当前行及后面所有行
from order_window
;

<a name="sWJSK"></a>

windows子句

带有窗口规范的OVER子句。窗口可以在WINDOW子句中单独定义。窗口规范支持如下格式:<br />

关键字 说明
PRECEDING 表示当前行之前的行
UNBOUNDED PRECEDING 表示当前行之前无边界行,即第一行
num PRECEDING 表示当前行之前第num行
CURRENT ROW 表示当前行
FOLLOWING 表示当前行后面的行
UNBOUNDED FOLLOWING 表示当前行后面无边界行,即最后一行
num FOLLOWING 表示当前行后面第num行

<br />当缺少WINDOW子句并指定使用ORDER BY时,窗口规范默认为RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,即从第一行到当前行。<br />当缺少ORDER BY和WINDOW子句时,窗口规范默认为ROW BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,即第一行到最后一行。<br />

<a name="fn1nr"></a>

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,695评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,569评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,130评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,648评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,655评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,268评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,835评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,740评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,286评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,375评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,505评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,873评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,357评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,466评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,921评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,515评论 2 359