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閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370