Hive的常用函数(nvl,case when,行转列,列转行,爆炸函数)

目录

综述:

 NVL:

case when:

行转列,CONCAT,CONCAT_WS,COLLECT_SET:

列转行:EXPLODE,LATERAL VIEW:


综述:

在Hive中有六类常用的函数,除了本文讲述的四类函数之外,还有rank函数,和开窗函数,Hive中的自定义函数一般被分成了三类

UDF:uer-defined-function 一进一出
UDAF:user-defined-aggregation-function 多进一出
UDTF:user-defined-generating-function 一进多出

我们可以通过相关的命令来获取某个函数的用法:

show functions  查询所有的自带函数
desc function extended case;  获得例子+用法
desc function case;  获得函数的用法

 NVL:

nvl(value,default_value)如果value为null,则返回default_value的值,否则返回value

select comm,nvl(comm,-1) from emp;
0: jdbc:hive2://hadoop108:10000> select comm,nvl(comm,-1) from emp;
+---------+---------+--+
|  comm   |   _c1   |
+---------+---------+--+
| NULL    | -1.0    |
| 300.0   | 300.0   |
| 500.0   | 500.0   |
| NULL    | -1.0    |
| 1400.0  | 1400.0  |
| NULL    | -1.0    |
| NULL    | -1.0    |
| NULL    | -1.0    |
| NULL    | -1.0    |
| 0.0     | 0.0     |
| NULL    | -1.0    |
| NULL    | -1.0    |
| NULL    | -1.0    |
| NULL    | -1.0    |
+---------+---------+--+

如果员工的comm为NULL,则用领导id代替
select comm,nvl(comm,mgr) from emp;
0: jdbc:hive2://hadoop108:10000> select comm,nvl(comm,mgr) from emp;
+---------+---------+--+
|  comm   |   _c1   |
+---------+---------+--+
| NULL    | 7902.0  |
| 300.0   | 300.0   |
| 500.0   | 500.0   |
| NULL    | 7839.0  |
| 1400.0  | 1400.0  |
| NULL    | 7839.0  |
| NULL    | 7839.0  |
| NULL    | 7566.0  |
| NULL    | NULL    |
| 0.0     | 0.0     |
| NULL    | 7788.0  |
| NULL    | 7698.0  |
| NULL    | 7566.0  |
| NULL    | 7782.0  |
+---------+---------+--+

case when:

[isea@hadoop108 datas]$ cat emp_sex.txt 
悟空		A	男
八戒		A	男
刘备		B	男
嫦娥		A	女
大乔		B	女
小乔		B	女


需求:求出部门和对应的员工的性别人数
A     2       1
B     1       2

创建hive表并导入数据:
create table emp_sex(name string,dept_id string,sex string)
row format delimited
fields terminated by '\t';

load data local inpath '/opt/module/datas/emp_sex.txt' into table emp_sex;
0: jdbc:hive2://hadoop108:10000> select * from emp_sex;
+---------------+------------------+--------------+--+
| emp_sex.name  | emp_sex.dept_id  | emp_sex.sex  |
+---------------+------------------+--------------+--+
| 悟空            | A                | 男            |
| 八戒            | A                | 男            |
| 刘备            | B                | 男            |
| 嫦娥            | A                | 女            |
| 大乔            | B                | 女            |
| 小乔            | B                | 女            |
+---------------+------------------+--------------+--+

> select dept_id,count(sex) from emp_sex group by dept_id;
+----------+------+--+
| dept_id  | _c1  |
+----------+------+--+
| A        | 3    |
| B        | 3    |
+----------+------+--+


我们来尝试分析一下,如果单纯的使用group by 对dept_id 分组和聚合函数sum,我们求的是部门下所有的
员工的总数,并不是对于区分性别,所以我们需要一种方式,当检查到sex为男的时候,记录一下man变量为
1,当检查到sex为女的时候对women 加1

所以使用下面的查询语句:
select dept_id,sum(case sex when '男' then 1 else 0 end) male_count,
sum(case sex when '女' then 1 else 0 end) female_count
from emp_sex group by dept_id;
+----------+-------------+---------------+--+
| dept_id  | male_count  | female_count  |
+----------+-------------+---------------+--+
| A        | 2           | 1             |
| B        | 1           | 2             |
+----------+-------------+---------------+--+

或者使用下面这种功能类似的写法
select dept_id,sum(case when sex = '男' then 1 else 0 end) male_count,
sum(case  when sex = '女' then 1 else 0 end) female_count
from emp_sex group by dept_id;

+----------+-------------+---------------+--+
| dept_id  | male_count  | female_count  |
+----------+-------------+---------------+--+
| A        | 2           | 1             |
| B        | 1           | 2             |
+----------+-------------+---------------+--+

行转列,CONCAT,CONCAT_WS,COLLECT_SET:

什么是行转列呢?

将类似于下面的形式:
A
B
C
转化为类似于下面的形式:
A B C 
即将多行转化为一行,排在一行了,就成了一列对吧

关于行转列主要有三个函数,

concat:
select concat('liubei','xihuan','xiaoqiao');

0: jdbc:hive2://hadoop108:10000> select concat('liubei','xihuan','xiaoqiao');
OK
+-----------------------+--+
|          _c0          |
+-----------------------+--+
| liubeixihuanxiaoqiao  |
+-----------------------+--+

concat_ws:
0: jdbc:hive2://hadoop108:10000> select concat_ws('|',array('liiubei','xihuan','xiaoqiao'));
OK
+--------------------------+--+
|           _c0            |
+--------------------------+--+
| liiubei|xihuan|xiaoqiao  |
+--------------------------+--+
1 row selected (0.096 seconds)

collect_set(col)将传入的内容去重,并放置到一个数组中。

[isea@hadoop108 datas]$ cat contellation.txt 
悟空		白羊座	A
张飞		射手座	A
刘备		白羊座	B
八戒		白羊座	A
小乔		射手座	A

创建hive表并导入数据:
create table person_info(name string,contellation string,blood_type string)
row format delimited
fields terminated by '\t';

load data local inpath '/opt/module/datas/contellation.txt' into table person_info;

0: jdbc:hive2://hadoop108:10000> select * from person_info;
OK
+-------------------+---------------------------+-------------------------+--+
| person_info.name  | person_info.contellation  | person_info.blood_type  |
+-------------------+---------------------------+-------------------------+--+
| 悟空                | 白羊座                       | A                       |
| 张飞                | 射手座                       | A                       |
| 刘备                | 白羊座                       | B                       |
| 八戒                | 白羊座                       | A                       |
| 小乔                | 射手座                       | A                       |
+-------------------+---------------------------+-------------------------+--+
把星座和血型一样的人归类到一起:

t:先将星座和血型归类到一起,
select name,concat(contellation,",",blood_type) base
from person_info;

+-------+--------+--+
| name  |  base  |
+-------+--------+--+
| 悟空    | 白羊座,A  |
| 张飞    | 射手座,A  |
| 刘备    | 白羊座,B  |
| 八戒    | 白羊座,A  |
| 小乔    | 射手座,A  |
+-------+--------+--+

select t.base,concat_ws('|',collect_set(name)) names
from (
select name,concat(contellation,",",blood_type) base
from person_info
) t
group by t.base;

+---------+--------+--+
| t.base  | names  |
+---------+--------+--+
| 射手座,A   | 张飞|小乔  |
| 白羊座,A   | 悟空|八戒  |
| 白羊座,B   | 刘备     |
+---------+--------+--+
这里使用group by 将base分组,使用collect_set将所有name去重后存放到一个数组中,在使用concat_ws
将数组中的元素连接起来。

列转行:EXPLODE,LATERAL VIEW

什么是列转行呢?

把类似于
A , B , C
转化为
A
B
C

列转行主要有两个函数:

select explode(array('liubei','zhangfei','guanyu'));
+-----------+--+
|    col    |
+-----------+--+
| liubei    |
| zhangfei  |
| guanyu    |
+-----------+--+
select explode(map('liubei','18','zhangfei','19'));

+-----------+--------+--+
|    key    | value  |
+-----------+--------+--+
| liubei    | 18     |
| zhangfei  | 19     |
+-----------+--------+--+


来看一下爆炸函数的局限性:在使用爆炸函数的时候,select后面只能跟爆炸函数,其他的不能跟
select '1',explode(array('liubei','zhangfei','guanyu'));
0: jdbc:hive2://hadoop108:10000> select '1',explode(array('liubei','zhangfei','guanyu'));
FAILED: SemanticException [Error 10081]: UDTF s are not supported outside the SELECT clause, nor nested in expressions


lateral view:斜写视图,为了解决爆炸函数的局限性,结合UDTF函数(如,explode())一起使用。
将电影分类中的数组数据展开
期望:
《疑犯追踪》      悬疑
《疑犯追踪》      动作
《疑犯追踪》      科幻
《疑犯追踪》      剧情
《Lie to me》   悬疑
《Lie to me》   警匪
《Lie to me》   动作
《Lie to me》   心理
《Lie to me》   剧情
《战狼2》        战争
《战狼2》        动作
《战狼2》        灾难


[isea@hadoop108 datas]$ cat move_info.txt 
《疑犯追踪》	悬疑,动作,科幻,剧情
《Lie to me》	悬疑,警匪,动作,心理,剧情
《战狼2》	战争,动作,灾难

创建hive表并导入数据:
create table movie_info(name string,category array)
row format delimited
fields terminated by '\t'
collection items terminated by ',';

load data local inpath '/opt/module/datas/move_info.txt' into table movie_info;

下面使用测写视图的方式,在求出爆炸函数结果的同时,求出除了爆炸函数字段之外的字段。需要添加爆炸之
后的表名,和爆炸之后的字段名,这个字段名可以放置于select之后,查询爆炸之后的字段值。

select name,category_info
from movie_info
lateral view explode(category) tmp_tbl as category_info;

+--------------+----------------+--+
|     name     | category_info  |
+--------------+----------------+--+
| 《疑犯追踪》       | 悬疑             |
| 《疑犯追踪》       | 动作             |
| 《疑犯追踪》       | 科幻             |
| 《疑犯追踪》       | 剧情             |
| 《Lie to me》  | 悬疑             |
| 《Lie to me》  | 警匪             |
| 《Lie to me》  | 动作             |
| 《Lie to me》  | 心理             |
| 《Lie to me》  | 剧情             |
| 《战狼2》        | 战争             |
| 《战狼2》        | 动作             |
| 《战狼2》        | 灾难             |
+--------------+----------------+--+


这里需要指出的是:在键表的时候一定不能对于集合数据类型,如果没有添加
collection items terminated by ','表中的数据是这样的:
+------------------+----------------------+--+
| movie_info.name  | movie_info.category  |
+------------------+----------------------+--+
| 《疑犯追踪》           | ["悬疑,动作,科幻,剧情"]      |
| 《Lie to me》      | ["悬疑,警匪,动作,心理,剧情"]   |
| 《战狼2》            | ["战争,动作,灾难"]         |
+------------------+----------------------+--+
category是一个完整的字符串,也即array中只有一个元素
添加了分隔符号之后是这样的:
+------------------+-----------------------------+--+
| movie_info.name  |     movie_info.category     |
+------------------+-----------------------------+--+
| 《疑犯追踪》           | ["悬疑","动作","科幻","剧情"]       |
| 《Lie to me》      | ["悬疑","警匪","动作","心理","剧情"]  |
| 《战狼2》            | ["战争","动作","灾难"]            |
+------------------+-----------------------------+--+

 

你可能感兴趣的:(bigData,Hive,Hive)