本文分享在Azure Databricks中如何實現行轉列和列轉行,並介紹對查詢的結果進行排序的各種方式。
一,行轉列
在分組中,把每個分組中的某一列的資料連線在一起:
- collect_list:把一個分組中的列合成為陣列,資料不去重,格式是['a','a','b']
- collect_set:把一個分組中的列合成為集合,資料去重,格式是['a','b']
用於連線文字陣列的函式,通過sep把陣列中的item分割開,連線成一個字串:
concat_ws(sep, [str | array(str)]+)
舉個例子,把每個使用者的game,通過逗號連線起來:
select uid ,concat_ws(",",collect_list(game)) as game_list from user_game
二,列轉行
Explode(expr) 用於處理array和map結構的資料,把一行的列值轉換成多行,該函式產生一個虛擬表,包含一行或多行資料,也就是說,Explode(expr)函式把array型別expr中的元素分成多行,或者將map型別的expr中的元素分成多行和多列。
舉個例子,把game_list中的每個item轉換為一行資料:
with cte_game as ( select uid ,collect_list(game) as game_list from user_game
group by uid ) select uid ,explode(game_list) as game from cte_game
三,Lateral View子句
Lateral View子句用於連線表值函式(UDTF),比如explode、split 。Lateral View通過UDTF函式把資料拆分成多行,再把多行結果組合成一個虛擬表。
該子句主要解決的問題是:在select使用UDTF做查詢的過程中,該查詢只能包含單個UDTF,不能包含其它欄位以及多個UDTF的情況。
LATERAL VIEW udtf(expression) tableAlias AS columnAlias (',' columnAlias)
使用LATERAL VIEW + explode 函式進行查詢,語句如下:
select movie,category_name from movie_info LATERAL VIEW explode(category) tmpTable as category_name; -- category_name 是給 explode(category) 列起的別名
四,排序
在SELECT子句中,ORDER BY子句用於保證最終資料的順序,除此之外,還可以按照分割槽來排序。
[ WITH with_query [ , ... ] ] select_statement[ ORDER BY { expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [ , ... ] } ] [ SORT BY { expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [ , ... ] } ] [ CLUSTER BY { expression [ , ... ] } ] [ DISTRIBUTE BY { expression [, ... ] } ] [ WINDOW { named_window [ , WINDOW named_window, ... ] } ]
1,DISTRIBUTE BY子句
根據輸入表示式對錶進行重新分割槽,
DISTRIBUTE BY { expression [ , ... ] }
舉個例子,把age相同的person作為同一個cluster(或partition)。
SELECT age, name FROM person DISTRIBUTE BY age;
2,SORT BY子句
在每個分割槽中,按照指定的順序對每個分割槽內的資料進行排序,如果分割槽不止一個,那麼SORT BY可能會返回部分排序的結果。
SORT BY { expression [ sort_direction | nulls_sort_order ] [ , ... ] }
引數註釋:
nulls_sort_order 的有效值是 NULLS { FIRST | LAST },可選,用於指定在非NULL值之前/之後是否返回NULL值。
如果未指定null_sort_order,則如果排序順序為ASC,則NULL排在最前面,如果排序順序為DESC,則NULL排在最後面。
- 如果指定了NULLS FIRST,則無論排序順序如何,都將首先返回NULL值。
- 如果指定了NULLS LAST,則無論排序順序如何,最後都會返回NULL值。
舉個例子,按照name對每個分割槽中的資料進行排序:
SELECT /*+ REPARTITION(zip_code) */ name, age, zip_code FROM person SORT BY name ASC, age DESC;
3,CLUSTER BY子句
根據輸入表示式對資料進行重新分割槽,然後對每個分割槽內的資料進行排序。從語義上講,這等效於先執行DISTRIBUTE BY,再執行SORT BY。該子句僅確保結果行在每個分割槽內排序,並且不保證輸出的總順序。
CLUSTER BY { expression [ , ... ] }
舉個例子,按照age把person分割槽,age相同的person位於同一個分割槽,然後按照age對每個分割槽中的person進行排序。
SELECT age, name FROM person CLUSTER BY age;
參考文件: