常用的内置函数
①空字段赋值:NVL
NVL:给值为NULL的数据赋值,它的格式是NVL( value,default_value)。
功能:如果value为NULL,则NVL函数返回default_value的值,否则返回value的值
如果两个参数都为NULL ,则返回NULL。
用法1:赋予一个常量
比如在员工表中就有很多空值,现在将奖金为空的员工赋值为0
select ename, sal, nvl(comm, 0) from emp;
nvl(comm, 0):当comm为null时,用0代替
用法2:赋予一个变量
当员工奖金为null时,用mgr代替
select ename, sal, nvl(comm, mgr) from emp;
②CASE WHEN THEN ELSE END
用法:
CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END
---> When a = b, returns c; when a = d, return e; else return f
当a=b,返回c;当a=d,返回e;否则返回f;
③行转列
1)CONCAT(string A/col, string B/col…):返回输入字符串连接后的结果,支持任意个输入字符串;
Example:
>>> SELECT concat('abc', 'def') FROM src LIMIT 1;
>>> 'abcdef'
将前后两个字符串连接起来
2)CONCAT_WS(separator, str1, str2,…):
Example:
>>> SELECT concat_ws('.', 'www', array('facebook', 'com')) FROM src LIMIT 1;
>>> 'www.facebook.com'
根据某个指定字符连接起来,支持连接array和字符串
3)COLLECT_SET(col):
它的主要作用是将某字段的值进行去重汇总,产生array类型字段。
4)示例:
需要达成的效果把星座和血型一样的人归类到一起。结果如下:
射手座,A 猪八戒|小白龙
白羊座,A 孙悟空|唐僧
白羊座,B 黑熊怪|沙和尚
(1)准备数据
vim /opt/module/hive/datas/concat.txt
孙悟空,白羊座,A
猪八戒,射手座,A
沙和尚,白羊座,B
唐僧,白羊座,A
小白龙,射手座,A
黑熊怪,白羊座,B
(2)创建person_info表并导入数据
create table person_info(
name string,
constellation string,
blood_type string
)
row format delimited
fields terminated by ",";
导入数据
load data local inpath '/opt/module/hive/datas/concat.txt' into table person_info;
(3)按照要求查询数据
SELECT
NAME,
CONCAT_WS(',',constellation,blood_type) c_b
FROM person_info;
select
t.c_b,
concat_ws('|', collect_set(t.name))
from(
SELECT
NAME,
CONCAT_WS(',',constellation,blood_type) c_b
FROM person_info
) t
group by t.c_b;
除了上述的写法,还可以在一个selct语句中实现
SELECT
concat_ws('|',COllect_set(concat_ws(',',constellation,blood_type))),
concat_ws('|',collect_set(name))
FROM person_info
group by constellation,blood_type;
④列转行
1)EXPLODE(col):
将hive一列中复杂的array或者map结构拆分成多行
2)SPLIT(string str, string regex):
按照regex字符串分割str,会返回分割后的字符串数组
3)LATERAL VIEW
用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias
用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,再将多行结果组合成一个支持别名的虚拟表
4)示例
需求:将电影分类中的categroy列的数据分开
movie category
《疑犯追踪》 悬疑,动作,科幻,剧情
《Lie to me》 悬疑,警匪,动作,心理,剧情
《战狼2》 战争,动作,灾难
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
《疑犯追踪》 悬疑
《疑犯追踪》 动作
《疑犯追踪》 科幻
《疑犯追踪》 剧情
《Lie to me》 悬疑
《Lie to me》 警匪
《Lie to me》 动作
《Lie to me》 心理
《Lie to me》 剧情
《战狼2》 战争
《战狼2》 动作
《战狼2》 灾难
(1)数据准备
vim /opt/module/hive/datas/movie_info.txt
《疑犯追踪》 悬疑,动作,科幻,剧情
《Lie to me》 悬疑,警匪,动作,心理,剧情
《战狼2》 战争,动作,灾难
(2)创建hive表并导入数据
create table if not exists movie_info(
movie string,
category string
)
row format delimited
fields terminated by '\t';
(3)导入数据
load data local inpath '/opt/module/hive/datas/movie_info.txt' into table test.movie_info;
(4)按需求查询数据
select movie, category_name
from movie_info
lateral view
explode(split(category, ',')) movie_temp
as category_name;
⑤窗口函数
1)相关函数说明
函数名 | 描述 | 用法 |
---|---|---|
over() | 指定分析函数工作的数据窗口大小, 这个数据窗口的大小可能会随着行的改变而改变 Current row: 当前行 n preceding:往前n行数据 n following:往后n行数据 unbounded preceding:表示从前面的起点 unbounded following:表示从后面的起点 | over(partition by name) over(order by orderdate) over(rows between and ) over(rows between unbounding preceding and unbounded following ) over(partition by name order by orderdate rows between n preceding and current) |
lag(col,n,default_val) | 往前第n行数据 | |
lead(col,n,default_val) | 往后第n行数据 | |
Ntile(n) | 把有序窗口的行分发到指定数据的组中,各个组的编号,编号从1开始,对于每一行,ntile返回此行所属的组的编号 注意:n必须为int类型 |
注意:
当有Order by ,没有WINDOW时, WINDOW的范围是,unbounded preceding and current row
select count(*) over(order by orderdate) from business where month(orderdate)=4;
当Order by和 WINDOW都没有时, WINDOW的范围是,unbounded preceding and unbounded following
select count(*) over() from business where month(orderdate)=4;
2)示例
(1)数据准备
vim /opt/module/hive/datas/business.txt
jack,2017-01-01,10
tony,2017-01-02,15
jack,2017-02-03,23
tony,2017-01-04,29
jack,2017-01-05,46
jack,2017-04-06,42
tony,2017-01-07,50
jack,2017-01-08,55
mart,2017-04-08,62
mart,2017-04-09,68
neil,2017-05-10,12
mart,2017-04-11,75
neil,2017-06-12,80
mart,2017-04-13,94
(2)创建hive表
create table if not exists business(
name string,
orderdate string,
cost int
)
row format delimited
fields terminated by ',';
(3)导入数据
load data local inpath '/opt/module/hive/datas/business.txt' into table test.business;
(4)需求
- 查询在2017年4月份购买过的顾客及总人数
- 查询顾客的购买明细及月购买总额
- 上述的场景, 将每个顾客的cost按照日期进行累加
- 查询每个顾客上次的购买时间
- 查询前20%时间的订单信息
(5)需求实现
1、查询在2017年4月份购买过的顾客及总人数
首先,如何查询出4月份购买过的顾客名单
select name from businee where month(orderdata)=4;
然后求出购买的总人数
select count(*) from business where month(orderdate)=4;
需要把所有的名字后面都添加一个总人数,使用窗口函数
select count(*) over() from business where month(orderdate)=4;
这种求得的总人数会把重复的也计算上去,所以分组求解
select count(*) over() from business where month(orderdate)=4;
将其组合在一起
select name, count(*) over() from business where month(orderdate)=4 group by name;
注意:如果日期并不是规则的格式,就不可以使用month进行月份判断,就可以使用分割字符substring进行处理
select name, count(*) over() from business where substring(orderdate, 1, 7)='2017-04' group by name;
2、查询顾客的购买明细及月购买总额
首先,如何查询顾客的购买明细
select name, count from business;
然后查询出月购买金额
select name, orderdate, cost, sum(cost) over(partition by name,month(orderdate)) from business;
3、将每个顾客的cost按照日期进行累加
将所有行进行累加
select name, orderdate, cost, sum(cost) over(partition by name order by month(orderdate)) from business;
将本行和前所有行进行累加
select name, cost, sum(cost)
over(
partition by name
order by month(orderdate)
rows between unbounded preceding and current row)
from business;
将本行只与前一行进行聚合
select name, cost, sum(cost)
over(
partition by name
order by month(orderdate)
rows between 1 preceding and 1 following
)
from business;
将本行与后面所有行进行聚合
select name, cost, sum(cost)
over(
partition by name
order by month(orderdate)
rows between current row and unbounded following
)
from business;
按照名字和月份分组,组内递增
select name, orderdate, cost, sum(cost)
over(
partition by name, month(orderdate)
order by day(orderdate)
rows between unbounded preceding and current row
)
from business;
(4)查看顾客上次的购买时间
lag(col, n, default_val):往前n行的数据col
select
name,
orderdate,
cost,
lag(orderdate,1,'1900-01-01') over(partition by name order by orderdate ) as time1,
lag(orderdate,2) over (partition by name order by orderdate) as time2
from business;
(5)查询前20%时间的订单信息
ntile(n):把有序窗口的行分发到指定数据的组中,各个组的编号,编号从1开始,对于每一行,ntile返回此行所属的组的编号
将数据按指定顺序分为n组
select * from (
select name,orderdate,cost, ntile(5) over(order by orderdate) sorted from business
) t
where sorted = 1;
order by还可以指定正序或降序
select * from (
select name,orderdate,cost, ntile(5) over(order by orderdate desc) sorted from business
) t
where sorted = 1;
⑥Rank
函数说明:
RANK() 排序相同时会重复,总数不会变
DENSE_RANK() 排序相同时会重复,总数会减少
ROW_NUMBER() 会根据顺序计算
有这么一张表的数据,按需要进行处理
1)按照学科对分数进行排序,重复时顺序相同,总数不变
select
name,
subject,
score,
rank() over(partition by subject order by score desc) sorts
from score;
2)按照学科对分数进行排序,重复时顺序相同,总数减少
select
name,
subject,
score,
dense_rank() over(partition by subject order by score desc) sorts
from score;
3)按照学科对分数进行排序,重复时顺序排列,总数不变
select
name,
subject,
score,
row_number() over(partition by subject order by score desc) sorts
from score;