# 一、问题介绍

在使用 explode 进行炸列操作时,发现炸列后有的行消失了。

# 二、模拟场景

建表语句
drop table test.shyl_explode_test;
create table test.shyl_explode_test(
    `id` string comment 'id',
    `list` ARRAY<string> comment '列表'
)comment'测试炸列函数所使用的字段为空时,该行数据如何处理'
stored as orc;
插入数据
INSERT INTO TABLE shyl_explode_test VALUES
  ('1', array('A', 'B', 'C')),
  ('2', array('X', 'Y')),
  ('3', array(""))
  ('4', null)
  ('5', array(null));

当插入数据 (‘4’, null) 报错 [42000][40000] Error while compiling statement: FAILED: SemanticException 0:0 Expected 2 columns for insclause-0/test@shyl_explode_test; select produces 1 columns. Error encountered near token 'TOK_NULL'

大概的意思是说这个 list 字段的数据类型是 array,现在要插入一个 null 类型的,类型不匹配,

但是在实际情况中,表中数据类型为 array,其值为 null 的情况不少见,比如我们是通过上传文件到 hdfs,再通过 hive 建表关联数据,得到的表【具体过程没有验证,不确定是是否可以创建成功】;执行连接操作时,没有关联上的使用 null 填充【未验证】; 或者只插入一个列的值,【本文就采取这种方式】,得到 list 字段为空的情况:

INSERT INTO TABLE shyl_explode_test(id) VALUES ('4');
查看表中的数据
select * from test.shyl_explode_test;
id list
1 [“A”,“B”,“C”]
2 [“X”,“Y”]
3 [""]
4 null
5 [null]
现根据list字段为null,查询出指定数据
select * from test.shyl_explode_test where list is null;
id list

发现数据为空,原因可能与字段类型为 array 有关

现提供一个其它的方式查询

因为size(map/array)返回 -1 作为特殊的值,通常表示一个无效或异常的情况,而不是实际的大小或长度,所以利用它来查询空值
select size(null);
-1
select * from test.shyl_explode_test where size(list)=-1;
id list
4 null

有关 sql 中的 null 参考此文:原文地址

# 三、执行 explode

select * from test.shyl_explode_test
lateral view explode(list)t1 as a;
id list a
1 [“A”,“B”,“C”] A
1 [“A”,“B”,“C”] B
1 [“A”,“B”,“C”] C
2 [“X”,“Y”] X
2 [“X”,“Y”] Y
3 [""]
5 [null] null

我们发现 id 为 4 的那一行数据缺失,现在是有两列,当我的列数多,且其它列的数据重要时,会发生丢失一些重要数据的情况。

所以在执行 explode 的时候添加一些保护机制,附上一些不影响结果的默认值。

select * from test.shyl_explode_test
lateral view explode(nvl(list,array(NULL)))t1 as a;
id list a
1 [“A”,“B”,“C”] A
1 [“A”,“B”,“C”] B
1 [“A”,“B”,“C”] C
2 [“X”,“Y”] X
2 [“X”,“Y”] Y
3 [""]
4 null null
5 [null] null

# 四、explode+lateral view 源码剖析

【目前不会看源码】,之后有能力补上,从结果反推,像是炸列后执行的 inner join。