背景
之前在下面这篇文档里,介绍了行转列的方法:
collect_list/set()
这里补齐列转行的方法(虽然用得很少)。
函数
1 split()
将字符串分割成数组。
split(string, pattern)
其中 pattern 是正则表达式,注意:
| 单字符类特殊字符(.) | 转义字符类特殊字符(\d) | |
|---|---|---|
| 不加转义符(\) | “.”,表示特殊字符 | “\d”,表示“d” | 
| 加转义符(\) | “\.”,表示“.” | “\\d”,表示特殊字符 | 
例如:
split("1,2,3", ",") = ["1", "2", "3"]
2 explode()
用于将数组转换成多行数据,可以近似实现“列(一个值)转行”的效果。
是一个 HIVE 内置的“表生成函数”
explode(array)
SELECT 一个 explode 结果是可以的,但不能直接 SELECT 多个字段其中包含 explode 结果,必须使用 LATERAL VIEW 进行视图拼接。意味着 SELECT province, explode(split(cities, ‘,’)) … 是错误的。
3 LATERAL VIEW
懒得翻译了。
Lateral view is used in conjunction with user-defined table generating functions such as explode(). As mentioned in Built-in Table-Generating Functions, a UDTF generates zero or more output rows for each input row. A lateral view first applies the UDTF to each row of base table and then joins resulting output rows to the input rows to form a virtual table having the supplied table alias.
LATERAL VIEW udtf(expression) tableAlias AS columnAlias
- 看上去,tableAlias 是这个 VIEW 实际的名字,但无法引用,所以更多时候用 columnAlias 直接在正文 SELECT 中查询。
 - 多个 LATERAL VIEW 可以拼接,生成笛卡尔积。
 - 不知道使用相同的 tableAlias 会是什么情况。
 - UDTF = User-Defined Table-generating Function。
 - 在这个场景中,UDTF = explode()。
 
例子
baseTable =
| A | B | 
|---|---|
| [a, b, c] | [1, 2, 3] | 
那么
SELECT LVA,BFROM baseTable LATERAL VIEW explode(split(A, ',')) tmp AS LVA
结果是:
| LVA | B | 
|---|---|
| a | [1, 2, 3] | 
| b | [1, 2, 3] | 
| c | [1, 2, 3] | 
联合两个
SELECT LVA,LVBFROM baseTable LATERAL VIEW explode(split(A, ',')) tmp1 AS LVA LATERAL VIEW explode(split(B, ',')) tmp2 AS LVB
结果是:
| LVA | LVB | 
|---|---|
| a | 1 | 
| a | 2 | 
| a | 3 | 
| b | 1 | 
| b | 2 | 
| b | 3 | 
| c | 1 | 
| c | 2 | 
| c | 3 | 
技巧
1 对位展开
如果想把上文的 baseTable 拆成这个样子:
| LVA | LVB | 
|---|---|
| a | 1 | 
| b | 2 | 
| c | 3 | 
可以使用 posexplode() 函数,该函数会提取索引值,另两张生成标(view)的索引值相等,即可对位取出想要的值,实际上还可以自定义 index 关系:
LATERAL VIEW posexplode(array) tableAlias AS columnId, columnAlias
这样搞:
SELECT LVA,LVBFROM baseTable LATERAL VIEW posexplode(split(A, ',')) tmp1 AS LVAid, LVA LATERAL VIEW posexplode(split(B, ',')) tmp2 AS LVBid, LVBWHERE LVAid = LVBid
从而实现想要的效果,因为此时 tmp1 结构是:
| LVAid | LVA | 
|---|---|
| 0 | a | 
| 1 | b | 
| 2 | c | 
同理,tmp2 结构是:
| LVBid | LVB | 
|---|---|
| 0 | 1 | 
| 1 | 2 | 
| 2 | 3 | 
2 空值保留
explode(array) 当 array 为空时不会生成空表格,而是不生成表格,这可能导致合并字段时丢失其他列的内容。
可以使用 OUTER 关键字解决这个问题,当 array 为空时,生成 null 值补位。
LATERAL VIEW OUTER udtf(expression) tableAlias AS columnAlias
参考
- 列转行分函数用法:https://blog.csdn.net/yahahassr/article/details/97911676
 - 解决多个 VIEW 笛卡尔积问题:https://blog.csdn.net/weixin_38073361/article/details/109386873
 - DOC about LATERAL VIEW:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+LateralView
 - Built-in Table-Generating Functions (UDTF):https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
 - posexplode 一个例子:https://blog.csdn.net/dzysunshine/article/details/101110467
 
