Hive经典例题解析

1.第一题:

sid  name  gender  age  academy  dt  chinese math english 
95001	李勇	男	20	CS	2017-08-31	56	28	62
95002	刘晨	女	19	IS	2017-08-31	84	22	38
95003	王敏	女	22	MA	2017-08-31	38	80	82
95004	张立	男	19	IS	2017-08-31	39	65	4
95005	刘刚	男	18	MA	2018-08-31	18	28	79
95006	孙庆	男	23	CS	2018-08-31	12	67	16
95007	易思玲	女	19	MA	2018-08-31	27	60	84
95008	李娜	女	18	CS	2018-08-31	12	12	82
95009	梦圆圆	女	18	MA	2018-08-31	62	35	94
95010	孔小涛	男	19	CS	2017-08-31	82	97	4
95011	包小柏	男	18	MA	2019-08-31	41	53	71
95012	孙花	女	20	CS	2017-08-31	90	51	79
95013	冯伟	男	21	CS	2019-08-31	20	69	86
95014	王小丽	女	19	CS	2017-08-31	83	64	60
95015	王君	男	18	MA	2019-08-31	39	48	29
95016	钱国	男	21	MA	2019-08-31	94	7	69
95017	王风娟	女	18	IS	2019-08-31	87	56	54
95018	王一啊	女	19	IS	2019-08-31	54	36	24
95019	邢小丽	女	19	IS	2018-08-31	78	9	82
95020	赵钱	男	21	IS	2019-08-31	4	48	87
95021	周二	男	17	MA	2018-08-31	84	61	16
95022	郑明	男	20	MA	2018-08-31	64	70	90
95023	李小勇	男	20	CS	2017-08-31	52	21	19
95024	刘小晨	女	19	IS	2017-08-31	1	16	76
95025	王小敏	女	22	MA	2017-08-31	13	89	98
95026	张小立	男	19	IS	2017-08-31	85	84	80
95027	刘小刚	男	18	MA	2018-08-31	7	17	48
95028	孙小庆	男	23	CS	2018-08-31	17	94	83
95029	易小思玲	女	19	MA	2018-08-31	69	84	23
95030	李小娜	女	18	CS	2018-08-31	16	70	70
95031	梦小圆	女	18	MA	2018-08-31	82	48	37
95032	孔涛	男	19	CS	2017-08-31	83	80	12
95033	包柏	男	18	MA	2019-08-31	18	16	71
95034	孙小花	女	20	CS	2017-08-31	36	95	93
95035	冯小伟	男	21	CS	2019-08-31	31	19	13
95036	王丽	女	19	CS	2017-08-31	16	42	9
95037	王小君	男	18	MA	2019-08-31	91	3	67
95038	钱小国	男	21	MA	2019-08-31	89	59	18
95039	王娟	女	18	IS	2019-08-31	7	17	67
95040	王小一	女	19	IS	2019-08-31	49	32	45
95041	邢丽	女	19	IS	2018-08-31	30	40	40
95042	赵小钱	男	21	IS	2019-08-31	71	69	57
95043	周小二	男	17	MA	2018-08-31	18	9	1
95044	郑一明	男	20	MA	2018-08-31	64	3	44
95045	张一勇	男	20	CS	2017-08-31	10	65	97
95046	刘一丽	女	19	IS	2017-08-31	56	8	45
95047	张一敏	女	22	MA	2017-08-31	19	8	98
95048	张一立	男	19	IS	2017-08-31	49	39	92
95049	刘一刚	男	18	MA	2018-08-31	4	79	91
95050	孙一庆	男	23	CS	2018-08-31	99	71	61
95051	易一玲	女	19	MA	2018-08-31	49	53	71
95052	李一	女	18	CS	2018-08-31	22	87	79
95053	小一	女	18	MA	2018-08-31	53	58	35
95054	孔一	男	19	CS	2017-08-31	30	62	5
95055	包一	男	18	MA	2019-08-31	73	68	28
95056	孙一庆	女	20	CS	2017-08-31	68	22	33
95057	冯一	男	21	CS	2019-08-31	91	26	46
95058	王一二	女	19	CS	2017-08-31	49	81	51
95059	王一三	男	18	MA	2019-08-31	56	27	49
95060	钱一	男	21	MA	2019-08-31	97	40	24
95061	王小娟	女	18	IS	2019-08-31	96	79	34
95062	王小一	女	19	IS	2019-08-31	87	6	55
95063	邢丽	女	19	IS	2018-08-31	56	19	33
95064	赵小钱	男	21	IS	2019-08-31	70	17	85
95065	周小二	男	17	MA	2018-08-31	66	19	14
95066	郑小明	男	20	MA	2018-08-31	99	95	14
95067	李勇	男	19	CS	2017-08-31	48	40	13
95068	刘晨	女	19	IS	2017-08-31	86	28	46
95069	王敏	女	21	MA	2017-08-31	91	59	0
95070	张立	男	17	IS	2017-08-31	99	39	64
95071	刘刚	男	20	MA	2018-08-31	73	2	64
95072	孙庆	男	19	CS	2018-08-31	90	71	5
95073	易思玲	女	19	MA	2018-08-31	72	87	25
95074	李娜	女	21	CS	2018-08-31	92	23	65
95075	梦圆圆	女	17	MA	2018-08-31	37	34	5
95076	孔小涛	男	20	CS	2017-08-31	15	37	40
95077	包小柏	男	19	MA	2019-08-31	29	82	30
95078	孙花	女	19	CS	2017-08-31	6	27	75
95079	冯伟	男	21	CS	2019-08-31	4	10	29
95080	王小丽	女	17	CS	2017-08-31	70	70	36
95081	王君	男	20	MA	2019-08-31	20	74	31
95082	钱国	男	19	MA	2019-08-31	59	85	39
95083	王风娟	女	19	IS	2019-08-31	6	98	95
95084	王一	女	21	IS	2019-08-31	16	26	27
95085	邢小丽	女	17	IS	2018-08-31	73	28	4
95086	赵钱	男	20	IS	2019-08-31	69	52	59
95087	周二	男	19	MA	2018-08-31	29	40	10
95088	郑明	男	18	MA	2018-08-31	77	13	91
95089	李勇	男	23	CS	2017-08-31	49	22	8
95090	刘晨	女	19	IS	2017-08-31	12	18	25
95091	王敏	女	18	MA	2017-08-31	44	94	47
95092	张立	男	18	IS	2017-08-31	71	45	17
95093	刘刚	男	19	MA	2018-08-31	27	90	50
95094	孙庆	男	18	CS	2018-08-31	92	34	75
95095	易思玲	女	20	MA	2018-08-31	38	63	24
95096	李娜	女	21	CS	2018-08-31	94	66	37
95097	梦圆圆	女	19	MA	2018-08-31	91	35	45
95098	孔小涛	男	18	CS	2017-08-31	9	61	0
95099	包小柏	男	19	MA	2019-08-31	93	66	25
95100	孙花	女	18	CS	2017-08-31	47	22	27
95101	冯伟	男	23	CS	2019-08-31	23	99	62
95102	王小丽	女	19	CS	2017-08-31	6	34	3
95103	王君	男	18	MA	2019-08-31	0	7	8
95104	钱国	男	18	MA	2019-08-31	93	2	35
95105	王风	女	19	IS	2019-08-31	12	84	50
95106	王一	女	18	IS	2019-08-31	29	60	86
95107	邢小	女	20	IS	2018-08-31	50	51	6
95108	赵钱	男	21	IS	2019-08-31	93	54	86
95109	周二	男	19	MA	2018-08-31	57	39	93
95110	郑明	男	18	MA	2018-08-31	30	78	62
95111	张勇	男	19	CS	2017-08-31	25	5	19
95112	刘丽	女	18	IS	2017-08-31	74	96	44
95113	张敏	女	23	MA	2017-08-31	64	17	82
95114	张小	男	19	IS	2017-08-31	14	57	69
95115	刘小	男	18	MA	2018-08-31	37	84	29
95116	孙小	男	18	CS	2018-08-31	7	99	26
95117	易小	女	19	MA	2018-08-31	60	97	26
95118	李小	女	18	CS	2018-08-31	57	8	88
95119	小小	女	20	MA	2018-08-31	7	97	64
95120	孔大	男	21	CS	2017-08-31	33	27	85
95121	包大	男	19	MA	2019-08-31	96	2	38
95122	孙小	女	18	CS	2017-08-31	54	94	23
95123	冯小伟	男	19	CS	2019-08-31	26	45	1
95124	王小丽	女	18	CS	2017-08-31	65	77	43
95125	王小君	男	23	MA	2019-08-31	24	22	34
95126	钱小国	男	19	MA	2019-08-31	98	98	2
95127	王小娟	女	18	IS	2019-08-31	36	66	30
95128	王小一	女	18	IS	2019-08-31	98	78	15
95129	邢丽	女	19	IS	2018-08-31	41	41	52
95130	赵小钱	男	18	IS	2019-08-31	87	65	93
95131	周小二	男	20	MA	2018-08-31	26	56	48
95132	郑小明	男	21	MA	2018-08-31	31	96	60
95133	李勇	男	19	CS	2017-08-31	26	53	78
95134	刘晨	女	18	IS	2017-08-31	60	27	11
95135	王敏	女	19	MA	2017-08-31	63	25	60
95136	张立	男	18	IS	2017-08-31	46	86	77
95137	刘刚	男	23	MA	2018-08-31	74	6	48
95138	孙庆	男	19	CS	2018-08-31	18	66	20
95139	易思玲	女	18	MA	2018-08-31	72	87	44
95140	李娜	女	18	CS	2018-08-31	12	68	55
95141	梦圆圆	女	19	MA	2018-08-31	63	70	29
95142	孔小涛	男	18	CS	2017-08-31	14	0	15
95143	包小柏	男	20	MA	2019-08-31	29	78	3
95144	孙花	女	21	CS	2017-08-31	1	21	86
95145	冯d伟	男	19	CS	2019-08-31	51	86	85
95146	王3丽	女	18	CS	2017-08-31	88	33	11
95147	王d君	男	23	MA	2019-08-31	61	98	29
95148	钱1国	男	19	MA	2019-08-31	88	65	12
95149	王2娟	女	18	IS	2019-08-31	30	64	41
95150	王B一	女	18	IS	2019-08-31	16	93	10
95151	邢A丽	女	19	IS	2018-08-31	58	20	24
95152	赵钱D	男	18	IS	2019-08-31	77	48	92
95153	周二C	男	20	MA	2018-08-31	89	7	60
95154	郑明B	男	21	MA	2018-08-31	18	76	59
95155	李勇A	男	19	CS	2017-08-31	53	35	49

1.1 将上面的数据存储到一个分区分桶表中。要求:分区按照学院和入学日期分区,根据学号分四个桶。

先建立一张含有基础信息的表格,学院跟日期不用填写进去,放在后面用于分桶,分区,
分区(partitioned by)记得添加名称和数据类型,
分桶 (clustered by) 格式如下

create table if not exists student_info(
sid int,
name string,
gender string,
age int,
chinese int,
math int,
english int
)
partitioned by (academy string,dt date)
clustered by (sid) sorted by (sid) into 4 buckets
row format delimited fields terminated by '\t';

再建立一张临时表,将所有信息放在上面,注意顺序,跟文本文件输入书序一致就行

create table if not exists tmp_student_info(
sid int,
name string,
gender string,
age int,
academy string,
dt date,
chinese int,
math int,
english int
)
row format delimited fields terminated by '\t'
;

在此之前需要找个目录,在目录下创建文本文件,输入下面的代码,
进入vim编辑模式,复制上面的输入信息,最后保存退出,
注意文本输入正确,不要多余空格跟字段,不然导致输入数据不正确

vim student_info.txt

接着载入文件,目录是我的目录,自己根据情况修改绿色地方的目录

load data local inpath '/data/tmp_student_info.txt' into table tmp_student_info;

再设置非严格模式

set hive.exec.dynamic.partition.mode=nonstrict

下面是动态输入的语句
insert into 接目标表格分区(partition)接select …from…临时表

这里注意!!!!!
前面几个sid,name,gender,age,chinese,math,english的数据信息要求跟目标表格顺序一致,否则报错,或者输出数据为Null,
代码输入顺序如下:
先目标表 后分区,再在from 临时表 后接分桶信息

insert overwrite table student_info partition(academy,dt)
select sid,name,gender,age,chinese,math,english,academy,dt from student_temp
distribute by (sid) sort by(sid);
insert into table student_info partition(academy,dt)
select sid,name,gender,age,chinese,math,english,academy,dt from student_temp cluster by(sid);

如果出现问题,检查表格,去vim里面查找文件问题,或者跟列明顺序有关,
这里不要用*来代替,

1.2 统计每个学院每年入学的总人数以及前一年的总人数。

先根据学院跟入学日期来分组,得到一张表 t
在根据表t 调用lag()序列函数 跟开窗函数来分区跟排序

lag(colname,num) lag返回当前数据行的前第n行的数据

select t.academy,t.dt,t.num,lag(t.num,1) over(distribute by t.academy sort by dt) `上一年的人数`
from
(select academy,dt,count(1) num
from student_info 
group by academy,dt
) t;

在这里插入图片描述

1.3 统计每个学院的男女人数,在一行上显示,并按照学院名称升序

查询效果如下:

学院    男     女
cs     xxx    xxx
MA     xxxx   xxx

使用sum(if()) 或者case when …then …end 都可以,
然后就是根据学院分组 group by
再者根据学院名称排序 order by

select academy,
sum(if(gender='男',1,0)) ``,
sum(if(gender='女',1,0)) ``
from student_info 
group by academy 
order by academy;

在这里插入图片描述

1.4 查询每个学院的每年入学总成绩排名的前五名的学生信息:连续,重复效果

(1).先建一张表t 包含学生id,姓名,跟总成绩的表

(2).再通过表t ,调用dense_rank() 的排名函数 根据学院分区,再根据成绩排序 形成表n

(3).最后给这个表n 添加条件(where) 排名为前5 即可

select *
from
(select *,dense_rank() over (distribute by t.academy sort by sum) num
from
(select sid,name,academy,chinese+math+english sum
 from student_info ) t
) n
where n.num <=5;

在这里插入图片描述

2.第二题

a_test、b_test、c_test三个hive表 每个表中都只有一列int类型且列名相同,求三个表中互不重复的数

a.txt

1
2
3
4
5
6
7
8
9

b.txt

2
3
11
12
14
15
16
18
35
6
7
8

c.txt

1
2
3
11
5
6
7
8
20
30
40

建表语句如下:

create table a_test(
id int
);

create table b_test(
id int
);

create table c_test(
id int
);
load data local inpath '/tmp/exercise/a.txt' into table a_test;
load data local inpath '/tmp/exercise/b.txt' into table b_test;
load data local inpath '/tmp/exercise/c.txt' into table c_test;

无脑的方法,用union all来去重连接三张表
统计出现次数为1的数

select A.id
from 
(select id from a_test union all
select id from b_test union all
select id from c_test) A
group by A.id having count(A.id)=1;

3.第三题

需求:词频统计。
统计结果如下,如果出现次数一样,则按照content名称排序:

content cnt
i 3
china 2
good 1
like 1
love 1
is 1

content_test表:

uid contents
1 i|love|china
2 china|is|good|i|i|like

建表语句

create table login_test(
uid int,
dt string,
login_status int
) 
row format delimited fields terminated by '\t';
load data local inpath '/tmp/exercise/content_test.txt' into table content_test;

解析:
通过explode()展开函数去展开,再用split()方法去根据 “ | ”来切除字符串,获取多个单词
注意: \用于转义字符 ,所以\\ = \ ,这里注意注意下就行了,
这样就得到表t
然后就是对表t 进行分组跟排序,再在select 上调用聚合函数算总数

select  content,count(1) cnt
from
(select explode(split(contents,'\\|')) content from content_test) t
group by t.content
order by cnt desc,content;

解法二:同思路,调用了lateral view

select content,count(1) num
from content lateral view explode(split(contents,"\\|")) mycontent as content
group by content
order by num desc,content

4.第四题

需求:求出连续七天登陆的总人数

数据: login_test表
uid dt login_status(1登录成功,0异常)

1	2019-07-11	1
1	2019-07-12	1
1	2019-07-13	1
1	2019-07-14	1
1	2019-07-15	1
1	2019-07-16	1
1	2019-07-17	1
1	2019-07-18	1
2	2019-07-11	1
2	2019-07-12	1
2	2019-07-13	0
2	2019-07-14	1
2	2019-07-15	1
2	2019-07-16	0
2	2019-07-17	1
2	2019-07-18	0
3	2019-07-11	1
3	2019-07-12	1
3	2019-07-13	1
3	2019-07-14	1
3	2019-07-15	1
3	2019-07-16	1
3	2019-07-17	1
3	2019-07-18	1

建表语句:

create table login_test(
uid int,
dt string,
login_status int
) 
row format delimited fields terminated by '\t';
load data local inpath '/tmp/exercise/login_test.txt' into table login_test;

解析:

1.首先通过 用序列函数根据uid 进行分区 然后根据dt 来排序 再用where 筛选出成功登录的信息 形成表 t1

select uid ,dt,row_number () over(distribute by uid sort by dt) rn
from login_test
where login_status =1

在这里插入图片描述

2.通过表t1 调用date_sub() 函数

这里有DATE_SUB(date,INTERVAL expr type) 的案例演示讲解

DATE_SUB(date,INTERVAL expr type)
date 参数是合法的日期表达式。
expr 参数是您希望添加的时间间隔。

date_sub(t1.dt,t1.rn)
通过输入的日期 dt,减去按时间排序的序号,如果最终指向同一天,那么他就是连续登录,如果不是同一天那么就是有断签的行为
最早的日期
3.最后根据uid,dt 进行分组,然后统计连续登录的人,并且次数大于等于7次
代码如下

select uid,dt,count(1)
from
(select t1.uid uid,date_sub(t1.dt,t1.rn) dt
from
(select uid ,dt,row_number () over(distribute by uid sort by dt) rn
from login_test
where login_status =1) t1) t2
group by uid,dt
having count(1)>=7

在这里插入图片描述

4.最后进行统计总人数,只能利用这样表t2 来分组count()来
最终代码如下:

select count(uid) `总人数`
from
(select uid,dt,count(1)
from
(select t1.uid uid,date_sub(t1.dt,t1.rn) dt
from
(select uid ,dt,row_number () over(distribute by uid sort by dt) rn
from login_test
where login_status =1) t1) t2
group by uid,dt
having count(1)>=7) t3;

解法二:
计算日期差值,因为实际日期包含当天所以去6

select count(distinct a.uid)
from
(select uid,login_status,
datediff(dt,lag(dt,6) over(distribute by uid sort by dt asc)) b
from login_test
where login_status=1) a
where a.b=6;

5.第五题

需求:现在要求使用hive,计算每一年的最大气温的日期+温度。
数据解析:比如:2010012325表示在2010年01月23日的气温为25度。
效果如下:

20010105        29
20070109        99
20080103        37
20100103        17
20120107        32
20130109        29
20140103        17
20150109        99

数据表如下:

2014010114
2014010216
2014010317
2014010410
2014010506
2012010609
2012010732
2012010812
2012010919
2012011023
2001010116
2001010212
2001010310
2001010411
2001010529
2013010619
2013010722
2013010812
2013010929
2013011023
2008010105
2008010216
2008010337
2008010414
2008010516
2007010619
2007010712
2007010812
2007010999
2007011023
2010010114
2010010216
2010010317
2010010410
2010010506
2015010649
2015010722
2015010812
2015010999
2015011023

建表语句:

create table if not exists temperature(
data string
)
row format delimited fields terminated by '\t'
lines terminated by '\n';

load data local inpath '/tmp/exercise/login_test.txt' into table login_test;

解析:
1.建表,通过substr( )函数进行字符串的截取,获取日期跟温度两个信息
再用dense_rank() 序列函数先对年份进行分区,再根据温度来降序排序,
得到表 t
substr()函数的实例讲解分析

select substr(data,0,8) dt,substr(data,9,11) tem,
dense_rank() over (distribute by substr(data,0,4) sort by substr(9,10) desc ) num
from temperature

在这里插入图片描述

2.筛选条件 num =1
就得出结果

select dt,tem
from
(select substr(data,0,8) dt,substr(data,9,11) tem,
dense_rank() over (distribute by substr(data,0,4) sort by substr(9,10) desc ) num
from temperature) t
where num=1;

在这里插入图片描述
解法二:
思路一致,只不过用max() 函数来解决,最后筛选条件是tem =max 就行

select dt,max
from
(select substr(data,0,8) dt,substr(data,9,11) tem,max(substr(data,9,11)) over (distribute by substr(data,0,4) ) max
 from temperature) t
where  tem=max;

5.第六题

需求:使用hql统计两个人的通话总时长(用户之间互相通话的时长)

有如下通话记录:
呼叫		被叫	  时长
goudan haoge 01:01:01
goudan mazi 00:11:21
goudan laowang 00:19:01
goudan Jingba 00:21:01
goudan weige 01:31:17
haoge mazi 00:51:01
haoge mazi 01:11:19
haoge laowang 00:00:21
haoge laowang 00:23:01
laowang mazi 01:18:01
laowang weige 00:18:00
Jingba haoge 00:01:01
Jingba haoge 00:00:06
Jingba haoge 00:02:04
Jingba haoge 00:02:54
haoge laowang 01:00:13
haoge laowang 00:01:01
haoge goudan 00:01:01

建表语句:

create table call_test(
huname string comment '主动呼叫用户名',
huiname string comment '被呼叫用户名',
times string comment '呼叫时间'
) 
row format delimited 
fields terminated by ' ';

load data local inpath '/tmp/exercise/call_test.txt' into table call_test;

解析:
1.通过case when then 来实现对通话者跟呼叫者进行变化,
假如有呼叫者跟通话这角色互调的情况,重新把他们归为一类,统一通话者跟呼叫者
所以表t1 就是这样的情况
在这里插入图片描述
2.然后进行分组,再对时间进行累加即可
(1) 这里原来times 时间是字符串类型,所以用hour(),min(),second() 函数统一转化为秒数

(2) 调用from_unixtime() 函数,后面将时间戳转化为日期类型,
这一点与unixtime()函数输入的内容和输出的内容正好相反

因为中国处于东八区(跟你的系统设置地区有关),
from_unixtime 是根据时间戳(具体时间数值)
准确来说是输入的是子午线的时间,
就会返回一个你所在的地区的时间
在这里插入图片描述

所以我计算得总秒数,返回的是东八区的时间,所以我们需要减去8小时的差值,所以就有了 - 28800 的由来

3.将两个内容嵌套就行了,根据呼叫者和通话者进行分组就OK了
最终代码如下:
from_unixtime()函数的讲解跟实例解析

select huname, huiname,
 from_unixtime(sum(hour(times)*3600+minute(times)*60+second(times))-28800,"HH:mm:ss" )
from
(select
   case when huname>=huiname then huname else huiname end huname,
   case when huname>=huiname then huiname else huname end huiname,
    times
 from call_test) t1
group by t1.huname,t1.huiname;

解法二:
思路相同这个会复杂一点,我推荐上面那种看得明白一点
先通过unixtime()函数得来对应时间的子午线时间,加上8小时,最终得到东八区时间,
之前说过,我们要得到的是子午线时间,所以需要减去28800,也就是后面那个unixtime()函数对应数值就是-28800
所以最终代码如下

select huname, huiname,
from_unixtime(sum(unix_timestamp(times,'HH:mm:ss')-unix_timestamp("00:00:00",'HH:mm:ss'))+unix_timestamp("00:00:00",'HH:mm:ss'),"HH:mm:ss") times
from
(select
case when huname>=huiname then huname else huiname end huname,
case when huname>=huiname then huiname else huname end huiname,
times
from call_test) t1
group by t1.huname,t1.huiname;

解法二:
连两张表分组跟条件排除,最后加的时间方法一致

select t.h1,t.h2,from_unixtime(sum(unix_timestamp(t.times,"HH:mm:ss")+28800)-28800,"HH:mm:ss") from
(
select huname h1,huiname h2,times
from call_test
union
select huiname h1,huname h2,times
from call_test
) t
where t.h1>t.h2 
group by t.h1,t.h2; 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值