Hive 的重要性不必多说,离线批处理的王者,Hive 用来做数据分析,SQL 基础必须十分牢固。
这里建4张表,下面的练习题都用这些数据。
-- 创建学生表
create table if not exists student_info(
stu_id string COMMENT '学生id',
stu_name string COMMENT '学生姓名',
birthday string COMMENT '出生日期',
sex string COMMENT '性别'
)
row format delimited fields terminated by ','
stored as textfile;
-- 创建课程表
create table if not exists course_info(
course_id string COMMENT '课程id',
course_name string COMMENT '课程名',
tea_id string COMMENT '任课老师id'
)
row format delimited fields terminated by ','
stored as textfile;
-- 创建老师表
create table if not exists teacher_info(
tea_id string COMMENT '老师id',
tea_name string COMMENT '学生姓名'
)
row format delimited fields terminated by ','
stored as textfile;
-- 创建分数表
create table if not exists score_info(
stu_id string COMMENT '学生id',
course_id string COMMENT '课程id',
score int COMMENT '成绩'
)
row format delimited fields terminated by ','
stored as textfile;
student_info.txt
001,彭于晏,1995-05-16,男
002,胡歌,1994-03-20,男
003,周杰伦,1995-04-30,男
004,刘德华,1998-08-28,男
005,唐国强,1993-09-10,男
006,陈道明,1992-11-12,男
007,陈坤,1999-04-09,男
008,吴京,1994-02-06,男
009,郭德纲,1992-12-05,男
010,于谦,1998-08-23,男
011,潘长江,1995-05-27,男
012,杨紫,1996-12-21,女
013,蒋欣,1997-11-08,女
014,赵丽颖,1990-01-09,女
015,刘亦菲,1993-01-14,女
016,周冬雨,1990-06-18,女
017,范冰冰,1992-07-04,女
018,李冰冰,1993-09-24,女
019,邓紫棋,1994-08-31,女
020,宋丹丹,1991-03-01,女
teacher_info.txt
1001,张高数
1002,李体音
1003,王子文
1004,刘丽英
course_info.txt
01,语文,1003
02,数学,1001
03,英语,1004
04,体育,1002
05,音乐,1002
score_info.txt
001,01,94
002,01,74
004,01,85
005,01,64
006,01,71
007,01,48
008,01,56
009,01,75
010,01,84
011,01,61
012,01,44
013,01,47
014,01,81
015,01,90
016,01,71
017,01,58
018,01,38
019,01,46
020,01,89
001,02,63
002,02,84
004,02,93
005,02,44
006,02,90
007,02,55
008,02,34
009,02,78
010,02,68
011,02,49
012,02,74
013,02,35
014,02,39
015,02,48
016,02,89
017,02,34
018,02,58
019,02,39
020,02,59
001,03,79
002,03,87
004,03,89
005,03,99
006,03,59
007,03,70
008,03,39
009,03,60
010,03,47
011,03,70
012,03,62
013,03,93
014,03,32
015,03,84
016,03,71
017,03,55
018,03,49
019,03,93
020,03,81
001,04,54
002,04,100
004,04,59
005,04,85
007,04,63
009,04,79
010,04,34
013,04,69
014,04,40
016,04,94
017,04,34
020,04,50
005,05,85
007,05,63
009,05,79
015,05,59
018,05,87
加载数据到 Hive 的数据源目录
load data local inpath '/opt/module/hive-3.1.2/datas/student_info.txt' into table student_info;
load data local inpath '/opt/module/hive-3.1.2/datas/teacher_info.txt' into table teacher_info;
load data local inpath '/opt/module/hive-3.1.2/datas/course_info.txt' into table course_info;
load data local inpath '/opt/module/hive-3.1.2/datas/score_info.txt' into table score_info;
重点就是一个 where ,可能涉及到一点多表联结。
简单的可以用 like 配合 % 和 _ ,复杂的可以使用 Hive 扩展的 rlike 配合正则表达式。
-- 查询姓名中带“冰”的学生名单
select * from student_info where stu_name like '%冰%';
-- 查询姓“王”老师的个数
select count(*) from teacher_info where tea_name like '王%';
-- 或者
select count(*) from teacher_info where tea_name rlike '^王';
通过 course_id 联结两张表,找到不及格的成绩所对应的课程信息。
select c.* from course_info c
join score_info s on c.course_id = s.course_id
where c.course_id = 4 and s.score < 60
order by s.score desc;
select stu.*,s.score from student_info stu
join (
select * from score_info
where course_id =
(select course_id from course_info where course_name = '数学')
)s
on s.stu_id = stu.stu_id
where s.score < 60
order by stu.stu_id;
这里需要注意的是,聚合函数必须要和 group by 配合使用!表示分组再做聚合处理。
--查询编号为“02”的课程的总成绩
select course_id,sum(score) from score_info where course_id = 02
group by course_id;
select count(distinct stu_id) from score_info;
重点就是一个 group by。
不同的科目对应不同的 course_id ,所以我们用 group by course_id。
-- 同样这里有聚合函数就必须配合 group by 来使用
select course_id,max(score) max,min(score) min from score_info
group by course_id;
select course_id, count(stu_id) from score_info
group by course_id;
-- 查询男生、女生人数
select sex,count(stu_id) from student_info
group by sex;
重点就是 group by 之后的条件判断语句用 having。
这里需要先分组后判断,所以不能用 where,因为 group by 后面的条件语句只能是 having。
-- 这里需要分组后再判断条件
select stu_id,avg(score) avg_score from score_info
group by stu_id
having avg_score>60;
-- 查询至少选修四门课程的学生学号
select stu_id,count(course_id) cnt from score_info
group by stu_id
having cnt>=4;
这里用到一个没用过的函数 substr() ,需要记忆一下。
select t1.first_name,count(stu_id) cnt from (
select *,substr(stu_name,0,1) first_name from student_info
)t1
group by t1.first_name
having cnt>=2;
多重排序判断直接逗号隔开即可。
-- 查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列
select course_id,avg(score) avg_score from score_info
group by course_id
order by avg_score,course_id desc ;
-- 统计参加考试人数大于等于15的学科
select course_id,count(*) cnt from score_info
group by course_id
having cnt>=15;
-- 查询学生的总成绩并按照总成绩降序排序
select stu_id,sum(score) sum_score from score_info
group by stu_id
order by sum_score desc;
这里用到了 Hive 中的 if 语句,它的语法是:
IF(condition, true_value, false_value)
其中,condition是要评估的条件,true_value是当条件为真时要返回的值,false_value是当条件为假时要返回的值。
比如;
SELECT name, age, IF(age >= 18, 'Adult', 'Minor') AS age_group
FROM users;
此外,还可以使用多重 if 嵌套语句:
SELECT name, age,
IF(age >= 18 AND gender = 'Male', 'Adult Male',
IF(age >= 18 AND gender = 'Female', 'Adult Female',
IF(age < 18 AND gender = 'Male', 'Minor Male', 'Minor Female'))) AS age_group
FROM users;
本题:这里的反引号是引用的作用,这里代表的是 列名。
select s.stu_id,
sum(if(c.course_name='语文',score,0)) `语文`,
sum(if(c.course_name='数学',score,0)) `数学`,
sum(if(c.course_name='英语',score,0)) `英语`,
count(*) `有效课程数`,
avg(s.score) `平均成绩`
from score_info s
join course_info c on s.course_id = c.course_id
group by s.stu_id
order by `平均成绩` desc ;
有点复杂,需要好好理解掌握。
-- 查询一共参加三门课程且其中一门为语文课程的学生的id和姓名
select t2.stu_id,s.stu_name from (
select t1.stu_id from (
select stu_id,course_id from score_info where stu_id in (
select stu_id from score_info
where course_id = '01'
) -- 筛选出有语文成绩的学生的id
) t1
group by t1.stu_id
having count(t1.course_id)=3
) t2
join student_info s on t2.stu_id = s.stu_id;
我们根据 stu_id 把每个学生的成绩信息聚合在一起。然后巧妙的使用了 if 语句来判断是否有不及格的科目,如果>=60分,结果+1,最后用 sum 函数统计出结果,如果 sum 等于0,则说明全部不及格。
-- 查询所有课程成绩均小于60分的学生的学号、姓名
select t1.stu_id,s.stu_name from(
select stu_id,sum(if(score>=60,1,0)) flag from score_info
group by stu_id
having flag=0
) t1
join student_info s on s.stu_id = t1.stu_id;
-- 查询没有学全所有课的学生的学号、姓名
select
s.stu_id,
s.stu_name
from student_info s
left join score_info sc on s.stu_id = sc.stu_id
group by s.stu_id, s.stu_name
having count(course_id) < (select count(course_id) from course_info)
select
s.stu_id,
s.stu_name
from student_info s
join (
select
stu_id,
count(course_id) course_count
from score_info
group by stu_id
having course_count =3
) t1
on s.stu_id = t1.stu_id;
4.1 表联结
4.2 多表连接