目录
0 需求描述
1 需求分析
2 小 结
0 需求描述
有如下表格
partner | label | value |
001 | 原始证件号 | 9111030275820228X7 |
001 | 统一社会信用代码 | 9111030275820228X7 |
002 | 原始证件号 | 6111030255820228Y7 |
002 | 统一社会信用代码 | 6111030255820228Y7 |
需要转换如下结果:
partner | 原始证件号 | 统一社会信用代码 |
001 | 9111030275820228X7 | 8111030275820228X7 |
002 | 6111030255820228Y7 | 5111030255820228Y7 |
![](https://img.php1.cn/3cd4a/1eebe/cd5/0a0ce631ec450943.webp)
1 需求分析
(1)创建数据
create table t as
select '001' as partner , '原始证件号' as label,'9111030275820228X7' as value
union all
select '001' as partner , '统一社会信用代码' as label,'8111030275820228X7' as value
union all
select '002' as partner , '原始证件号' as label,'6111030255820228Y7' as value
union all
select '002' as partner , '统一社会信用代码' as label,'5111030255820228Y7' as value
(2) 数据分析
方法1:借助于聚合函数max()与case when实现。代码如下
select partner,max(case when label='原始证件号' then value else null end) as a,max(case when label='统一社会信用代码' then value else null end) as b
from t
group by partner
利用max()函数可以有效的去除NULL值,max()函数在计算的时候会忽略NULL值
方法2:借助于str_to_map实现
str_to_map(字符串参数, 分隔符1, 分隔符2)
使用两个分隔符将文本拆分为键值对。
分隔符1将文本分成K-V对,分隔符2分割每个K-V对。对于分隔符1默认分隔符是 ',',对于分隔符2默认分隔符是 '='
测试如下:
select str_to_map('aaa:11&bbb:22', '&', ':')+--------------------------+
| _c0 |
+--------------------------+
| {"bbb":"22","aaa":"11"} |
+--------------------------+
2 rows selected (2.226 seconds)
结果返回一个json对象。其中第一个参数用来分割整个串,指名需要按照哪个符号来分割K-V对,第二个参数用来指明K-V对中的分隔符。
从这测试案例也可以看出如果需要将数据拼接成一个json数组,也可以使用str_to_map的形式。
针对本问题:我们先做如下变换
第一步:先将label 和value拼接成K-V对
select concat_ws(':',label,value)from t +------------------------------+
| _c0 |
+------------------------------+
| 统一社会信用代码:8111030275820228X7 |
| 原始证件号:9111030275820228X7 |
| 原始证件号:6111030255820228Y7 |
| 统一社会信用代码:5111030255820228Y7 |
+------------------------------+
第二步: 利用collect_list()函数将多行转成单列
select concat_ws(',',collect_list(concat_ws(':',label,value))) from t group by partner+----------------------------------------------------+
| _c0 |
+----------------------------------------------------+
| 原始证件号:6111030255820228Y7,统一社会信用代码:5111030255820228Y7 |
| 统一社会信用代码:8111030275820228X7,原始证件号:9111030275820228X7 |
+----------------------------------------------------+
第三步:利用str_to_map()函数组合成json形式
select str_to_map(concat_ws(',',collect_list(concat_ws(':',label,value))),',',':' )from t group by partner+----------------------------------------------------+
| _c0 |
+----------------------------------------------------+
| {"原始证件号":"6111030255820228Y7","统一社会信用代码":"5111030255820228Y7"} |
| {"统一社会信用代码":"8111030275820228X7","原始证件号":"9111030275820228X7"} |
+----------------------------------------------------+
第四步:map结构的取数方式进行行转列。具体SQL如下
select partner,mmap['原始证件号'] as a ,mmap['统一社会信用代码'] as b from (select partner,str_to_map(concat_ws(',',collect_list(concat_ws(':',label,value))),',',':' ) as mmapfrom t group by partner) t
+----------+---------------------+---------------------+
| partner | a | b |
+----------+---------------------+---------------------+
| 002 | 6111030255820228Y7 | 5111030255820228Y7 |
| 001 | 9111030275820228X7 | 8111030275820228X7 |
+----------+---------------------+---------------------+2 rows selected (1.178 seconds)
方法1和方法2对比来看,方法2采用str_to_map的方法更优雅,效率更高一点,这是因为hive底层在这种高级的数据结构上做了优化,逻辑更优一点。
2 小 结
本文分析了一种采用str_to_map的方法进行行转列的方法,该方法结构优雅,从执行效率上来看性能更优,比通用的聚合函数加case when的方法效率更高。通过本文也可以利用str_to_map来拼接json串,不失为一种很好的技巧。