复杂数据类型一共有四种:
- ARRAY:数组
- MAP:键值对
- STRUCT:命名字段集合
- UNION:从几种数据类型中指明选择一种,UNION的值必须于这些数据类型之一完全匹配;
所用函数说用:
列转行
- EXPLODE(col): 将 hive 一列复杂的 array 或者 map 结构拆分成多行。
- LATERAL VIEW
用法:LATERAL VIEW udtf(expression) tableAlias as columnAlias
解释:用于和 split,explode 等 UDTF一起使用,它能够将一系列数据拆成多行,在此基础上可以对拆分后的数据进行聚合。
行转列
- CONCAT(string A/col, string B/col...): 返回输入字符串连接后的结果,支持任意个输入字符串;
- CONCAT_WS(separator,str1,str2,...): 它是一个特殊形式的 CONCAT()。第一个参数剩余参数见的分隔符。分隔符可以是与剩余参数一样的字符串。如果分隔符是NULL,返回值也将为NULL。这个函数会跳过分隔符参数后的任何NULL和空字符串。分隔符将被加到被连接的字符串之间;
- COLLECT_SET(col):函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型的字段。
ARRAY
- 创建名为 t2的表,只有 person 和 friends 两个字段, person 是字符串类型, friends 是数组类型,通过文本文件导入数据时,person 和 friends之间的分隔符是竖线,friends 内部的多个元素之间的分隔符是逗号,
注意分隔符的语法:
create table if not exists t2( person string, friends array<string> ) row format delimited fields terminated by '|' collection items terminated by ',';
-
创建文本文件002.txt, 内容如下:可见只有两条记录,第一条person字段值为 tom,friends字段里面有三个元素,用逗号分隔:
tom|tom_friend_0,tom_friend_1,tom_friend_2 jerry|jerry_friend_0,jerry_friend_1,jerry_friend_2,jerry_friend_3,jerry_friend_4,jerry_friend_5
-
执行以下语句,从本地的 002.txt文件导入数据到 t2表:
load data local inpath '/home/hadoop/temp/202010/25/002.txt' into table t2;
-
查看全部数据:
hive> select * from t2; ok t2.person t2.friends tom ["tom_friend_0","tom_friend_1","tom_friend_2"] jerry["jerry_friend_0","jerry_friend_1","jerry_friend_2","jerry_friend_3","jerry_friend_4"]
-
查询friends 中的某个元素的SQL:
select person,friends[0],friend[3] from t2;
执行结果如下,第一条记录没有 friends[3],显示为NULL:
hive > select person,friends[0],friends[3] from t2; OK person _c1_c2 tom tom_friend_0 NULL jerry jerry_friend_0 jerry_friend_3
-
数组元素中是否包含某值的SQL:
select person, array_contains(friends,'tom_friend_0') from t2;
执行结果如下,第一条记录 friends数组中有 tom_friend_0 , 显示为 true,第二条记录不包含, 就显示为 false:
hive > select person,array_contains(friends,'tom_friend_0') from t2; OK person _c1 tom true jerry false
-
第一条记录的friends数组中有三个元素,借助 LATERAL VIEW语法可以把这三个元素 拆成三行,SQL如下:
select t.person,single_friend from( select person,friends from t2 where person='tom' ) t LATERAL VIEW explode(t.friends) v as single_friend;
执行结果如下,可见数组中的每个元素都能拆成单独一行:
OK t.person single_friend tom tom_friend_0 tom tom_friend_1 tom tom_friend_2
以上就是数组的基本操作,接下来是键值对;
MAP,建表,导入数据
- 接下来打算创建名为 t3 的表, 只有 person 和 address 两个字段, person 是字符串类型, address 是 MAP类型,通过文本文件导入数据时,对分隔符的定义如下:
- person 和 adress 之间的分隔符 是 竖线;
- address内部有多个键值对,他们的分隔符是逗号;
- 而每个键值对的键和值的分隔符是冒号;
- 满足上述要求的建表语句如下:
create table if not exists t3( person string, address map<string,string> ) row format delimited fields terminated by '|' collection items terminated by ',' map keys terminated by ':';
- 创建文本文件 003.txt, 可见用了三种分隔符来 分隔字段、MAP中的多个元素、每个元素键和值:
tom|province:guangdong,city:shenzhen jerry|province:jiangsu,city:nanjing
- 导入003.txt数据到 t3表:
load data local inpath '/home/hadoop/temp/202010/25/003.txt' into table t3;
MAP ,查询
- 查看全部数据:
hive > select * from t3; OK t3.person t3.address tom {"province":"guangdong","city":"shenzhen"} jerry {"province":"jiangsu","city":"nanjing"}
-
查看MAP中某个key,语法是 field["xxx"]:
hive> select person,adress["province"] from t3; OK person _c1 tom guangdong jerry jiangsu
-
使用if 函数,下面的SQL是判断 address 字段中是否有 "street"键, 如果有就显示对应的值,没有就显示 field street not exists:
select person, if(address['street'] is null,"filed street not exists",address['street']) from t3;
输出如下,由于 address 字段只有 province 和 city 两个键, 因此会显示 filed street not exists:
OK tom filed street not exists jerry filed street not exists
-
使用 explode 将 address 字段的每个键值对展示成一行:
hive > select explode(address) from t3; OK key value province guangdong city shenzhen province jiangsu city nanjing
-
上面的explode函数只能展示 address 字段,如果还要展示其他字段就要继续 LATERAL VIEW语法,如下,可见前面的数组展开为一个字段,MAP展开为两个字段,分别是key和value:
select t.person, address_key,address_value from( select person,address from t3 where person='tom' ) t LATERAL VIEW explode(t.address) v as address_key,address_value;
结果如下:
OK t.person address_key address_value tom province guangdong tom city shenzhen
-
size函数可以查看MAP中键值对的数量:
hive> select person,size(address) from t3; OK tom 2 jerry 2
STRUCT
- STRUCT是一种记录类型,它封装了一个命名的字段集合,里面有很多属性,新建名为 t4 的表,其 info字段就是STRUCT类型,里面有 age 和 city 两个属性,person 和 info 之间的分隔符是竖线,info内部的多个元素之间的分隔符是逗号,注意声明分隔符的语法:
create table if not exists t4( person string, info struct<age:int,city:string> ) row format delimited fields terminated by '|' collection items terminated by ',';
- 准备好的名为 004.txt的文本文件,内容如下:
tom|11,shenzhen jerry|12,nanjing
- 加载 004.txt 的数据到 t4表:
load data local inpath '/opt/module/hive/temp/004.txt' into table t4;
- 查看 t4中的所有数据:
hive (default)> select * from t4; OK t4.person t4.info tom {"age":11,"city":"shenzhen"} jerry {"age":12,"city":"nanjing"} Time taken: 0.091 seconds, Fetched: 2 row(s)
- 查看指定字段,用filedname.xxx语法:
hive (default)> select person,info.city from t4; OK person city tom shenzhen jerry nanjing Time taken: 0.085 seconds, Fetched: 2 row(s)
UNION
- 最后一种是 UNIONTYPE, 这是从几种数据类型中指明选择一种,由于UNIONTYPE数据的创建设计到 UDF(create_union),这里先不展开了,先看看建表语句:
create table union_test(foo UNIONTYPE<int,double,array<string>,struct<a:int,b:string>>);
-
查询结果: