目錄
0 引 言
分析函數在sql中非常重要,對於sqlboy來說是必須要掌握的 ,本文對Hive-Sql分析函數進行彙總和總結,Hive-Sql分析函數主要有以下五類:
- 聚合分析函數
- 排名分析函數
- 數學分析函數
- 行偏移量分析函數
- 多維分析函數
其思維導圖如下所示:
1. 聚合分析函數
- sum 求和
- count 統計記錄數
- min 求最小值
- max 求最大值
- avg 求均值
2.排名分析函數
- ROW_NUMBER 正常排序(行號)[1,2,3,4] -- 必須有order_by。適合於生成主鍵,連續序列或者不併列排名
- RANK 跳躍排序[1,2,2,4] -- 必須有order_by
- DENSE_RANK 密集排序/等位排序[1,2,2,3] -- 必須有order_by
- FIRST 從DENSE_RANK返回的集合中取出排在最前面的一個值的行
- LAST 從DENSE_RANK返回的集合中取出排在最後面的一個值的行
- FIRST_VALUE 返回窗口中第一行某字段值,取分組內排序後,截止到當前行,第一行某字段值
- LAST_VALUE 返回窗口中的最後一行某字段值,取分組內排序後,截止到當前行,最後一行某字段值
3.數學分析函數
- NTILE 用於將分組數據按照順序切分成n片(n桶),返回當前切片值(桶序號).切片值就是桶的序號。類似於hive中分桶,用於求百分比
對於一組數字(1,2,3,4,5,6),ntile(2)切片後爲(1,1,1,2,2,2)
(1,2,3,4,5,6,7),ntile(2)切片後爲(1,1,1,1,2,2,2)
其序號的標定類似於hive中分桶的原理。
又叫分桶函數或分片函數。ntile(n),n表示分桶或分片的個數。
- COVAR_POP 返回一對錶達式的總體協方差
- COVAR_SAMP 返回一對錶達式的樣本協方差
- CUME_DIST 計算一行在組中的相對位置。小於等於當前值的行數/分組內總行數
- PERCENT_RANK 分組內當前行的RANK值-1/分組內總行數-1
- PERCENTILE_DISC 返回一個與輸入的分佈百分比值相對應的數據值
舉例如下:
數據準備:
d1,user1,1000
d1,user2,2000
d1,user3,3000
d2,user4,4000
d2,user5,5000
CREATE EXTERNAL TABLE lxw1234 (
dept STRING,
userid string,
sal INT
) ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
stored as textfile location '/tmp/lxw11/';
hive> select * from lxw1234;
OK
d1 user1 1000
d1 user2 2000
d1 user3 3000
d2 user4 4000
d2 user5 5000
CUME_DIST
–CUME_DIST 小於等於當前值的行數/分組內總行數
–比如,統計小於等於當前薪水的人數,所佔總人數的比例
SELECT
dept,
userid,
sal,
CUME_DIST() OVER(ORDER BY sal) AS rn1,
CUME_DIST() OVER(PARTITION BY dept ORDER BY sal) AS rn2
FROM lxw1234;
dept userid sal rn1 rn2
-------------------------------------------
d1 user1 1000 0.2 0.3333333333333333
d1 user2 2000 0.4 0.6666666666666666
d1 user3 3000 0.6 1.0
d2 user4 4000 0.8 0.5
d2 user5 5000 1.0 1.0
rn1: 沒有partition,所有數據均爲1組,總行數爲5,
第一行:小於等於1000的行數爲1,因此,1/5=0.2
第三行:小於等於3000的行數爲3,因此,3/5=0.6
rn2: 按照部門分組,dpet=d1的行數爲3,
第二行:小於等於2000的行數爲2,因此,2/3=0.6666666666666666
SELECT
dept,
userid,
sal,
PERCENT_RANK() OVER(ORDER BY sal) AS rn1, --分組內
RANK() OVER(ORDER BY sal) AS rn11, --分組內RANK值
SUM(1) OVER(PARTITION BY NULL) AS rn12, --分組內總行數
PERCENT_RANK() OVER(PARTITION BY dept ORDER BY sal) AS rn2
FROM lxw1234;
dept userid sal rn1 rn11 rn12 rn2
---------------------------------------------------
d1 user1 1000 0.0 1 5 0.0
d1 user2 2000 0.25 2 5 0.5
d1 user3 3000 0.5 3 5 1.0
d2 user4 4000 0.75 4 5 0.0
d2 user5 5000 1.0 5 5 1.0
rn1: rn1 = (rn11-1) / (rn12-1)
第一行,(1-1)/(5-1)=0/4=0
第二行,(2-1)/(5-1)=1/4=0.25
第四行,(4-1)/(5-1)=3/4=0.75
rn2: 按照dept分組,
dept=d1的總行數爲3
第一行,(1-1)/(3-1)=0
第三行,(3-1)/(3-1)=1
4.不同行字段值比較分析函數(行偏移量分析函數)
- LAG 可以訪問結果集中的其它行而不用進行自連接。可以訪問當前行之前的行,前偏移量函數,如果沒有指定,偏移量默認爲1
- LEAD LEAD與LAG相反,LEAD可以訪問當前行之後的行,後偏移量函數,用法同LAG函數
*注:以上兩個函數功能非常強大,使用較廣 ,可以跨行取任意一個字段的值進行分析比較,採用上述函數避免了自連接操作,提高了效率。面試中也經常會被考察到,如求連續三天登錄的用戶等問題。
5.多維分析函數
- GROUPING SETS 在一個GROUP BY查詢中,根據不同的維度組合進行聚合,等價於將不同維度的GROUP BY結果集進行UNION ALL
- GROUPING__ID 表示結果屬於哪一個分組集合
- CUBE 根據GROUP BY的維度的所有組合進行聚合
- ROLLUP 是CUBE的子集,以最左側的維度爲主,從該維度進行層級聚合。
數據準備:
2015-03,2015-03-10,cookie1
2015-03,2015-03-10,cookie5
2015-03,2015-03-12,cookie7
2015-04,2015-04-12,cookie3
2015-04,2015-04-13,cookie2
2015-04,2015-04-13,cookie4
2015-04,2015-04-16,cookie4
2015-03,2015-03-10,cookie2
2015-03,2015-03-10,cookie3
2015-04,2015-04-12,cookie5
2015-04,2015-04-13,cookie6
2015-04,2015-04-15,cookie3
2015-04,2015-04-15,cookie2
2015-04,2015-04-16,cookie1
CREATE EXTERNAL TABLE lxw1234 (
month STRING,
day STRING,
cookieid STRING
) ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
stored as textfile location '/tmp/lxw11/';
hive> select * from lxw1234;
OK
2015-03 2015-03-10 cookie1
2015-03 2015-03-10 cookie5
2015-03 2015-03-12 cookie7
2015-04 2015-04-12 cookie3
2015-04 2015-04-13 cookie2
2015-04 2015-04-13 cookie4
2015-04 2015-04-16 cookie4
2015-03 2015-03-10 cookie2
2015-03 2015-03-10 cookie3
2015-04 2015-04-12 cookie5
2015-04 2015-04-13 cookie6
2015-04 2015-04-15 cookie3
2015-04 2015-04-15 cookie2
2015-04 2015-04-16 cookie1
GROUPING SETS
在一個GROUP BY查詢中,根據不同的維度組合進行聚合,等價於將不同維度的GROUP BY結果集進行UNION ALL
SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM lxw1234
GROUP BY month,day
GROUPING SETS (month,day)
ORDER BY GROUPING__ID;
month day uv GROUPING__ID
------------------------------------------------
2015-03 NULL 5 1
2015-04 NULL 6 1
NULL 2015-03-10 4 2
NULL 2015-03-12 1 2
NULL 2015-04-12 2 2
NULL 2015-04-13 3 2
NULL 2015-04-15 2 2
NULL 2015-04-16 2 2
等價於
SELECT month,NULL,COUNT(DISTINCT cookieid) AS uv,1 AS GROUPING__ID FROM lxw1234 GROUP BY month
UNION ALL
SELECT NULL,day,COUNT(DISTINCT cookieid) AS uv,2 AS GROUPING__ID FROM lxw1234 GROUP BY day
再如:
SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM lxw1234
GROUP BY month,day
GROUPING SETS (month,day,(month,day))
ORDER BY GROUPING__ID;
month day uv GROUPING__ID
------------------------------------------------
2015-03 NULL 5 1
2015-04 NULL 6 1
NULL 2015-03-10 4 2
NULL 2015-03-12 1 2
NULL 2015-04-12 2 2
NULL 2015-04-13 3 2
NULL 2015-04-15 2 2
NULL 2015-04-16 2 2
2015-03 2015-03-10 4 3
2015-03 2015-03-12 1 3
2015-04 2015-04-12 2 3
2015-04 2015-04-13 3 3
2015-04 2015-04-15 2 3
2015-04 2015-04-16 2 3
等價於
SELECT month,NULL,COUNT(DISTINCT cookieid) AS uv,1 AS GROUPING__ID FROM lxw1234 GROUP BY month
UNION ALL
SELECT NULL,day,COUNT(DISTINCT cookieid) AS uv,2 AS GROUPING__ID FROM lxw1234 GROUP BY day
UNION ALL
SELECT month,day,COUNT(DISTINCT cookieid) AS uv,3 AS GROUPING__ID FROM lxw1234 GROUP BY month,day
其中的 GROUPING__ID,表示結果屬於哪一個分組集合。
CUBE
根據GROUP BY的維度的所有組合進行聚合。
SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM lxw1234
GROUP BY month,day
WITH CUBE
ORDER BY GROUPING__ID;
month day uv GROUPING__ID
--------------------------------------------
NULL NULL 7 0
2015-03 NULL 5 1
2015-04 NULL 6 1
NULL 2015-04-12 2 2
NULL 2015-04-13 3 2
NULL 2015-04-15 2 2
NULL 2015-04-16 2 2
NULL 2015-03-10 4 2
NULL 2015-03-12 1 2
2015-03 2015-03-10 4 3
2015-03 2015-03-12 1 3
2015-04 2015-04-16 2 3
2015-04 2015-04-12 2 3
2015-04 2015-04-13 3 3
2015-04 2015-04-15 2 3
等價於
SELECT NULL,NULL,COUNT(DISTINCT cookieid) AS uv,0 AS GROUPING__ID FROM lxw1234
UNION ALL
SELECT month,NULL,COUNT(DISTINCT cookieid) AS uv,1 AS GROUPING__ID FROM lxw1234 GROUP BY month
UNION ALL
SELECT NULL,day,COUNT(DISTINCT cookieid) AS uv,2 AS GROUPING__ID FROM lxw1234 GROUP BY day
UNION ALL
SELECT month,day,COUNT(DISTINCT cookieid) AS uv,3 AS GROUPING__ID FROM lxw1234 GROUP BY month,day
是CUBE的子集,以最左側的維度爲主,從該維度進行層級聚合。
比如,以month維度進行層級聚合:
SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM lxw1234
GROUP BY month,day
WITH ROLLUP
ORDER BY GROUPING__ID;
month day uv GROUPING__ID
---------------------------------------------------
NULL NULL 7 0
2015-03 NULL 5 1
2015-04 NULL 6 1
2015-03 2015-03-10 4 3
2015-03 2015-03-12 1 3
2015-04 2015-04-12 2 3
2015-04 2015-04-13 3 3
2015-04 2015-04-15 2 3
2015-04 2015-04-16 2 3
可以實現這樣的上鑽過程:
月天的UV->月的UV->總UV
--把month和day調換順序,則以day維度進行層級聚合:
SELECT
day,
month,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM lxw1234
GROUP BY day,month
WITH ROLLUP
ORDER BY GROUPING__ID;
day month uv GROUPING__ID
-------------------------------------------------------
NULL NULL 7 0
2015-04-13 NULL 3 1
2015-03-12 NULL 1 1
2015-04-15 NULL 2 1
2015-03-10 NULL 4 1
2015-04-16 NULL 2 1
2015-04-12 NULL 2 1
2015-04-12 2015-04 2 3
2015-03-10 2015-03 4 3
2015-03-12 2015-03 1 3
2015-04-13 2015-04 3 3
2015-04-15 2015-04 2 3
2015-04-16 2015-04 2 3
可以實現這樣的上鑽過程:
天月的UV->天的UV->總UV
(這裏,根據天和月進行聚合,和根據天聚合結果一樣,因爲有父子關係,如果是其他維度組合的話,就會不一樣)
這種函數,需要結合實際場景和數據去使用和研究,只看說明的話,很難理解。
參考鏈接