多行合併經常使用於作區間統計,經過定義必定的金額區級,將上億的記錄降維爲不一樣區間內總數。歸納來講就是多映射到一。
典型場景:
基於用戶交易天流水,計算天天不一樣金額段的金額筆數。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
爲何不使用下面這種寫法函數
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進行處理。ui
在hive的表中,有些記錄多是NULL,這時若是咱們直接對這條記錄作運算或邏輯判斷是得不到咱們指望的結果的,這裏能夠將NULL轉換爲0再作處理。
固然NULL轉0能夠使用hive現成的函數nvl,這裏使用CASE WHEN是想介紹在hive sql裏條件語句的用法。spa
如上表記錄用戶天天的收入以及支出,天天的收入和支出可能爲空,須要計算用戶連續兩天的總收入以及總支出。
使用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,原來的多列轉化爲多行。
以下排序
這裏有兩種方式能夠實現,分佈是使用union以及posexplode。圖片
union實現方式就是分佈取出單列,而後進行對結果進行合併,sql以下。
it
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)轉換後,能夠得到列名在數組中的位置,這樣將位置對應一列進行輸出便可。io
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