介紹一些常見的數據分析場景中hive sql的一些寫法,涉及區間分析,數據按條件轉換,數據列轉行,計算連續天數,分組排序取top N等場景。sql
多行合併經常使用於作區間統計,經過定義必定的金額區級,將上億的記錄降維爲不一樣區間內總數。歸納來講就是多映射到一。 典型場景: 基於用戶交易天流水,計算天天不一樣金額段的金額筆數。數組
如用戶的天交易流水表結構如上,須要計算出交易額在0-100,100-200,200-300,大於300幾個區級的筆數,函數
CREATE VIEW t_deal_tmp_view_1 AS
SELECT
CASE
WHEN rcv_amount <= 100 THEN 1
WHEN rcv_amount <= 200 THEN 2
WHEN rcv_amount <= 300 THEN 3
ELSE 4 END AS amount_range,
receiver
FROM t_transfer_info
SELECT
amount_range,
COUNT(receiver) AS cnt
FROM t_deal_tmp_view_1
GROUP BY amount_range
DROP VIEW t_deal_tmp_view_1
複製代碼
爲何不使用下面這種寫法ui
SELECT
CASE
WHEN rcv_amount <= 100 THEN 1
WHEN rcv_amount <= 200 THEN 2
WHEN rcv_amount <= 300 THEN 3
ELSE 4 END AS amount_range,
COUNT(receiver)
FROM t_transfer_info
GROUP BY
CASE
WHEN rcv_amount <= 100 THEN 1
WHEN rcv_amount <= 200 THEN 2
WHEN rcv_amount <= 300 THEN 3
ELSE NULL END
複製代碼
這種寫法會報Expressio Not In Group By Key 的錯誤,在hive中, 使用Group By時,非Group By的字段必須使用聚合函數,只有Group By的字段才能原值取出。
主要緣由是上面在Group By後面使用Case When沒方法命名新字段。 所以須要使用臨時view進行處理。spa
在hive的表中,有些記錄多是NULL,這時若是咱們直接對這條記錄作運算或邏輯判斷是得不到咱們指望的結果的,這裏能夠將NULL轉換爲0再作處理。 固然NULL轉0能夠使用hive現成的函數nvl,這裏使用CASE WHEN是想介紹在hive sql裏條件語句的用法。3d
如上表記錄用戶天天的收入以及支出,天天的收入和支出可能爲空,須要計算用戶連續兩天的總收入以及總支出。 使用join將兩天的表連接進行計算,對於NULL使用替換爲0,sql以下:code
SELECT
t1.uin,
t1.income + CASE WHEN t2.income IS NULL THEN 0 ELSE t2.income END AS income,
t1.expend + CASE WHEN t2.expend IS NULL THEN 0 ELSE t2.expend END AS expend
FROM
(
SELECT
uin,
income,
expend
FROM t_user_trans_inf_day
WHERE statis_day=20180812
)t1
LEFT JOIN
(
SELECT
uin,
income,
expend
FROM t_user_trans_inf_day
WHERE statis_day=20180811
)t2
ON(t1.uin=t2.uin)
複製代碼
若有一個表A,如上,記錄了用戶的消費記錄,每類消費一列,如今須要將該表的列轉化爲行,如表B,原來的多列轉化爲多行。 以下cdn
這裏有兩種方式能夠實現,分佈是使用union以及posexplode。blog
union實現方式就是分佈取出單列,而後進行對結果進行合併,sql以下。 排序
SELECT uin, 1 AS type, of_amt
FROM t_user_trans
UNION ALL
SELECT uin, 2 AS type, lf_amt
FROM t_user_trans
UNION ALL
SELECT uin, 3 AS type, on_amt
FROM t_user_trans
UNION ALL
SELECT uin, 4 AS type, cr_amt
FROM t_user_trans
複製代碼
explode是內建函數, 支持兩種用法分別是:
explode(ARRAY) 列表中的每一個元素生成一行。
explode(MAP) map中每一個key-value對,生成一行,key爲一列,value爲一列。
使用explode(ARRAY)沒有type列,所以沒法將轉換後的行對應到以前的列,這裏能夠使用posexplode來代替,posexplode(ARRAY)轉換後,能夠得到列名在數組中的位置,這樣將位置對應一列進行輸出便可。
SELECT
uin
t.pos+1 AS type,
t.value AS amount
FROM t_user_tans
LATERAL VIEW
posexplode(
ARRAY(
of_amt,
lf_amt,
on_amt,
cr_amt
)) t as pos, value
複製代碼
有一張用戶登錄流水錶,須要計算用戶的連續登錄天數,這裏能夠使用分組編號,Group By uin+時間減分組編號,這樣連續的天數就被聚合在一塊兒了,能夠經過聚合函數計算最終結果。
SELECT
uin,
COUNT(uin) AS continuity_days
FROM(
SELECT
uin,
statis_day,
row_number() OVER(PARTITION BY uin order by statis_day asc) AS rn
FROM
(
SELECT
uin,
statis_day
FROM t_user_login_log
WHERE statis_day>= 20170101
AND statis_day <= 20180809
)
)
GROUP BY uin, date_sub(statis_day,CAST(rn AS INT))
複製代碼
如有t_user_score記錄了學生全部的科目成績,須要取出每一個學生分數最高的一門學科。這裏主要用到row_number()函數。
SELECT
uin
FROM
(
SELECT
uin,
course,
row_number() OVER(PARTITION BY uin order by score asc) AS rn
FROM
t_user_score
)
WHERE rn = 1
複製代碼