如何在Hive SQL中将列名与对应列值拆分为多行输出
Hive宽表转Key-Value长表实现方案
需求说明
现有Hive源表(假设表名为source_table)包含4个字段:ID、acno、date、tranym,需要将每行的每个字段拆分为独立行,最终输出两列:
col_1:存储原表的字段名col_2:存储对应字段的取值
示例源数据:
| ID | acno | date | tranym |
|---|---|---|---|
| AA | 12345 | 20170505 | 201705 |
| BB | 67890 | 20180604 | 201806 |
转换后输出结果:
| col_1 | col_2 |
|---|---|
| ID | AA |
| acno | 12345 |
| date | 20170505 |
| tranym | 201705 |
| ID | BB |
| acno | 67890 |
| date | 20180604 |
| tranym | 201806 |
实现SQL
全版本兼容写法(支持所有Hive版本)
SELECT col_1, col_2 FROM source_table LATERAL VIEW POSEXPLODE(ARRAY('ID', 'acno', 'date', 'tranym')) t1 AS pos, col_1 LATERAL VIEW POSEXPLODE(ARRAY(CAST(ID AS STRING), CAST(acno AS STRING), CAST(date AS STRING), CAST(tranym AS STRING))) t2 AS pos2, col_2 WHERE t1.pos = t2.pos;
高版本简化写法(支持Hive 2.3及以上)
SELECT col_1, col_2 FROM source_table LATERAL VIEW INLINE( ARRAY( STRUCT('ID' AS col_1, CAST(ID AS STRING) AS col_2), STRUCT('acno' AS col_1, CAST(acno AS STRING) AS col_2), STRUCT('date' AS col_1, CAST(date AS STRING) AS col_2), STRUCT('tranym' AS col_1, CAST(tranym AS STRING) AS col_2) ) ) t;
实现原理说明
- 核心逻辑是通过Hive的
LATERAL VIEW语法配合UDTF(用户自定义表生成函数),对源表的每一行输入生成多行输出,完成列转行操作。 - 全版本兼容写法原理:
- 用
ARRAY函数将所有字段名按固定顺序拼接为数组,再将所有字段值按相同顺序拼接为另一个数组,所有字段值统一转为STRING类型保证数组元素类型一致,避免语法报错。 - 用
POSEXPLODE函数将两个数组分别炸开,返回每个元素的位置索引和元素本身。 - 通过
WHERE条件过滤两个炸开结果位置相同的行,保证字段名和对应取值一一匹配。
- 用
- 高版本简化写法原理:
直接将每个字段的名称和取值拼成STRUCT结构,再把所有STRUCT拼接为数组,用INLINE函数直接将STRUCT数组炸开为多行多列,无需额外关联位置索引,语法更简洁执行效率也更高。
注意事项
- 若需要保留原行的归属标识,可以在
SELECT中增加原表的唯一标识字段(如原表ID字段)即可。 - 所有字段值统一转
STRING是必须操作,否则如果源表字段类型不同,会触发数组元素类型不一致的报错。
内容的提问来源于stack exchange,提问作者Jung Hyun Lee
相关产品推荐
相关产品推荐

