hive sql常用技巧

1.多行合併

多行合併常用於做區間統計,通過定義一定的金額區級,將上億的記錄降維爲不同區間內總數。概括來說就是多映射到一。
典型場景:
基於用戶交易天流水,計算每天不同金額段的金額筆數。

圖片描述

如用戶的天交易流水錶結構如上,需要計算出交易額在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 

爲什麼不使用下面這種寫法

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進行處理。

2.使用條件語句將NULL轉爲0

在hive的表中,有些記錄可能是NULL,這時如果我們直接對這條記錄做運算或邏輯判斷是得不到我們期望的結果的,這裏可以將NULL轉換爲0再做處理。
當然NULL轉0可以使用hive現成的函數nvl,這裏使用CASE WHEN是想介紹在hive sql裏條件語句的用法。

圖片描述

如上表記錄用戶每天的收入以及支出,每天的收入和支出可能爲空,需要計算用戶連續兩天的總收入以及總支出。
使用join將兩天的錶鏈接進行計算,對於NULL使用替換爲0,sql如下:

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)

3.列傳行

圖片描述

如有一個表A,如上,記錄了用戶的消費記錄,每類消費一列,現在需要將該表的列轉化爲行,如表B,原來的多列轉化爲多行。
如下

圖片描述

這裏有兩種方式可以實現,分佈是使用union以及posexplode。

方法一 使用union

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
方法二,使用posexplode

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

4.計算連續天數

有一張用戶登陸流水錶,需要計算用戶的連續登陸天數,這裏可以使用分組編號,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))

5.分組排序取topN

如有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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章