Hive SQL初级练习(30题)

简介: Hive SQL初级练习(30题)

前言

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;

第一章 简单查询

1.1、查找特定条件

重点就是一个 where ,可能涉及到一点多表联结。

1.1.1 查询姓名中带“冰”的学生名单

简单的可以用 like 配合 % 和 _ ,复杂的可以使用 Hive 扩展的 rlike 配合正则表达式。

-- 查询姓名中带“冰”的学生名单
select * from student_info where stu_name like '%冰%';

1.1.2 查询姓“王”老师的个数

-- 查询姓“王”老师的个数
select count(*) from teacher_info where tea_name like '王%';
-- 或者
select count(*) from teacher_info where tea_name rlike '^王';

1.1.3 检索课程编号为“04”且分数小于60的学生的课程信息,结果按分数降序排列

通过 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;


1.1.4 查询数学成绩不及格的学生和其对应的成绩,按照学号升序排序

  1. 查询数学课对应的 course_id
  2. 通过该 course_id 在 score_info 表中查出不及格的成绩的学生信息
  3. 通过学生信息中的 stu_id 字段将 score_info 表和 student_info 表联结起来,输出需要的字段(学生信息,成绩)。
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;

第二章 汇总分析

2.1 汇总分析

这里需要注意的是,聚合函数通常和 group by 配合使用!表示分组再做聚合处理。

2.1.1 查询编号为“02”的课程的总成绩

--查询编号为“02”的课程的总成绩
select course_id,sum(score) from score_info where course_id = 02
group by course_id;

2.1.2 查询参加考试的学生个数

select count(distinct stu_id) from score_info;

2.2 分组

重点就是一个 group by。

2.2.1 查询各科成绩最高和最低的分,显示格式:课程号,最高分,最低分

不同的科目对应不同的 course_id ,所以我们用 group by course_id。

-- 同样这里有聚合函数配合 group by 来使用
select course_id,max(score) max,min(score) min from score_info
group by course_id;

2.2.2 查询每门课程有多少学生参加了考试

select course_id, count(stu_id) from score_info
group by course_id;

2.2.3 查询男生、女生人数

-- 查询男生、女生人数
select sex,count(stu_id) from student_info
group by sex;

2.3 分组结果的条件

重点就是 group by 之后的条件判断语句用 having。

2.3.1 查询平均成绩大于60分的学生的学号和平均成绩

这里需要先分组后判断,所以不能用 where,因为 group by 后面的条件语句只能是 having。

-- 这里需要分组后再判断条件
select stu_id,avg(score) avg_score from score_info
group by stu_id
having avg_score>60;

2.3.2 查询至少选修四门课程的学生学号

-- 查询至少选修四门课程的学生学号
select stu_id,count(course_id) cnt from score_info
group by stu_id
having cnt>=4;

2.3.3 查询同姓的学生名单并统计同姓人数大于2的姓

这里用到一个没用过的函数 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;

2.3.4 查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列

多重排序判断直接逗号隔开即可。

-- 查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列
select course_id,avg(score) avg_score from score_info
group by course_id
order by avg_score,course_id desc ;

2.3.5 统计参加考试人数大于等于15的学科

-- 统计参加考试人数大于等于15的学科
select course_id,count(*) cnt from score_info
group by course_id
having cnt>=15;

2.4 查询结果排序&分组指定条件

2.4.1 查询学生的总成绩并按照总成绩降序排序

-- 查询学生的总成绩并按照总成绩降序排序
select stu_id,sum(score) sum_score from score_info
group by stu_id
order by sum_score desc;

2.4.2 按照 学生id  语文    数学    英语   有效课程数      平均成绩 的格式输出成绩,没有成绩的记为 0

这里用到了 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 ;

2.4.3 查询一共参加三门课程且其中一门为语文课程的学生的id和姓名

有点复杂,需要好好理解掌握。

-- 查询一共参加三门课程且其中一门为语文课程的学生的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;

第三章 复杂查询

3.1 子查询

3.1.1 查询所有课程成绩均小于60分的学生的学号、姓名

我们根据 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;

3.1.2 查询没有学全所有课的学生的学号、姓名

这里需要注意:

  1. 在Hive SQL中,子查询的结果可能返回多行数据,因此需要使用IN关键字而不是=关键字。IN关键字用于匹配子查询结果中的任何一个值,而=关键字只能匹配单个值。
  2. group by 不一定必须和聚合函数搭配使用,比如下面的查询 course_info 表的行数。
-- 查询没有学全所有课的学生的学号、姓名
select stu_id, stu_name
from student_info
where stu_id not in (
    select stu_id
    from score_info
    group by stu_id
    having count(distinct course_id) = (select count(distinct course_id) from course_info)
);

3.1.3 查询出只选修了三门课程的全部学生的学号和姓名

这里同样需要注意:当子查询的结果是多行值时,用 in 而不是 = !

-- 查询出只选修了三门课程的全部学生的学号和姓名
select stu_id,stu_name from student_info where stu_id in (
    select stu_id from score_info
    group by stu_id
    having count(course_id)=3
    );

第四章 多表查询

4.1 表联结

4.1.1 查询有两门以上的课程不及格的同学的姓名及其平均成绩

-- 查询有两门以上的课程不及格的同学的姓名及其平均成绩
select stu_name,avg_score from student_info st join (
    select stu_id,avg(score) avg_score from score_info
    group by stu_id
    having sum(if(score<60,1,0))>=2) t1
on st.stu_id=t1.stu_id;

4.1.2 查询所有学生的学号、姓名、选课数、总成绩

-- 查询所有学生的学号、姓名、选课数、总成绩
select t1.stu_id,s.stu_name,cnt,sum_score from (
    select stu_id,count(course_id) cnt,sum(score) sum_score from score_info
    group by stu_id)t1 join student_info s
on t1.stu_id=s.stu_id;

4.1.3 查询平均成绩大于85的所有学生的学号、姓名和平均成绩

-- 查询平均成绩大于85的所有学生的学号、姓名和平均成绩
select t1.stu_id,s.stu_name,avg from (
    select stu_id,avg(score) avg from score_info
    group by stu_id
    having avg>85)t1 join student_info s
on t1.stu_id=s.stu_id;

4.1.4 查询学生的选课情况:学号,姓名,课程号,课程名称

-- 查询学生的选课情况:学号,姓名,课程号,课程名称
select t1.stu_id,s.stu_name,t1.course_id,c.course_name from(
    select stu_id,course_id from score_info)t1
join student_info s
on t1.stu_id=s.stu_id
join course_info c
on c.course_id=t1.course_id;

输出结果明显按照科目分开, 前几行都是选语文的学生信息。

或者

-- 查询学生的选课情况:学号,姓名,课程号,课程名称
select t1.stu_id,s.stu_name,t1.course_id,c.course_name from(
    select stu_id,course_id from score_info
    group by stu_id, course_id)t1
join student_info s
on t1.stu_id=s.stu_id
join course_info c
on c.course_id=t1.course_id;

这里的输出结果明显按照姓名分开,前几行都是同一个学生的选课信息(这里的 group by要么指定两个字段(即我们要查询的 stu_id 和 course_id),要么就不需要 group by)。

4.1.5 查询出每门课程的及格人数和不及格人数

-- 查询出每门课程的及格人数和不及格人数
select c.course_name,`及格人数`,`不及格人数` from (
    select course_id,sum(if(score>=60,1,0)) `及格人数`,sum(if(score<60,1,0)) `不及格人数` from score_info
    group by course_id)t1
join course_info c
on t1.course_id=c.course_id;

4.1.6 查询课程编号为03且课程成绩在80分以上的学生的学号和姓名及课程信息

这里需要注意如果查询结果中没有用到聚合函数就少用 group by,因为group by会触发生成 mapreduce 程序;能用 where 最好,因为 where 不会触发产生 mapreduce 程序;where 可以秒出结果,而 group by需要好多秒。

-- 查询课程编号为03且课程成绩在80分以上的学生的学号和姓名及课程信息
select t1.stu_id,s.stu_name,c.course_name from (
    select stu_id,course_id from score_info
    where course_id=03 and score>80)t1
join course_info c
on t1.course_id=c.course_id
join student_info s
on t1.stu_id=s.stu_id;

4.2 多表连接

4.2.1 课程编号为"01"且课程分数小于60,按分数降序排列的学生信息

-- 课程编号为"01"且课程分数小于60,按分数降序排列的学生信息
select s.*,t1.score from student_info s join (
    select stu_id,score from score_info
    where course_id=01 and score<60)t1
on s.stu_id=t1.stu_id
order by t1.score desc;

4.2.2 查询所有课程成绩在70分以上的学生的姓名、课程名称和分数,按分数升序排列

-- 查询所有课程成绩在70分以上的学生的姓名、课程名称和分数,按分数升序排列
select s.stu_id,s.stu_name,c.course_name,s2.score from student_info s
join (
    select stu_id,sum(if(score>=70,0,1)) flag from score_info
    group by stu_id
    having flag=0) t1
on s.stu_id=t1.stu_id
left join score_info s2
on s.stu_id=s2.stu_id
left join course_info c
on s2.course_id=c.course_id;

4.2.3 查询该学生不同课程的成绩相同的学生编号、课程编号、学生成绩

-- 查询该学生不同课程的成绩相同的学生编号、课程编号、学生成绩
select sc1.stu_id,sc1.course_id,sc1.score from score_info sc1
join score_info sc2
on sc1.stu_id=sc2.stu_id
and sc1.course_id <> sc2.course_id
and sc1.score=sc2.score;

4.2.4 查询课程编号为“01”的课程比“02”的课程成绩高的所有学生的学号

-- 查询课程编号为“01”的课程比“02”的课程成绩高的所有学生的学号
select s1.stu_id from (
    select stu_id,course_id,score from score_info sc1
    where sc1.course_id=01) s1
join (
    select sc2.stu_id,sc2.course_id,sc2.score from score_info sc2
    where sc2.course_id=02) s2
on s1.stu_id=s2.stu_id
where s1.score>s2.score;

4.2.5 查询学过编号为“01”的课程并且也学过编号为“02”的课程的学生的学号、姓名

-- 查询学过编号为“01”的课程并且也学过编号为“02”的课程的学生的学号、姓名
select s.stu_id,s.stu_name from(
    select stu_id,sum(if(course_id=01,1,0)+if(course_id=02,1,0)) sumOfCourse from score_info
    group by stu_id)t1
join student_info s
on t1.stu_id=s.stu_id
where sumOfCourse=2;

4.2.6 查询学过“李体音”老师所教的所有课的同学的学号、姓名

-- 查询学过“李体音”老师所教的所有课的同学的学号、姓名
select t1.stu_id,si.stu_name
from(
    select stu_id from score_info si
    where course_id in
    (
        select course_id from course_info c
        join teacher_info t
        on c.tea_id = t.tea_id
        where tea_name='李体音'      --李体音教的所有课程
    )
    group by stu_id
    having count(*)=2       --学习所有课程的学生
)t1
left join student_info si
on t1.stu_id=si.stu_id;

4.2.7 查询学过“李体音”老师所讲授的任意一门课程的学生的学号、姓名

select
    t1.stu_id,
    si.stu_name
from
(
    select
        stu_id
    from score_info si
    where course_id in
    (
        select
           course_id
        from course_info c
        join teacher_info t
        on c.tea_id = t.tea_id
        where tea_name='李体音'
    )
    group by stu_id
)t1
left join student_info si
on t1.stu_id=si.stu_id;

4.2.8 查询没学过"李体音"老师讲授的任一门课程的学生姓名

select
    stu_id,
    stu_name
from student_info
where stu_id not in
(
    select
        stu_id
    from score_info si
    where course_id in
    (
        select
           course_id
        from course_info c
        join teacher_info t
        on c.tea_id = t.tea_id
        where tea_name='李体音'
    )
    group by stu_id
);

4.2.9 查询至少有一门课与学号为“001”的学生所学课程相同的学生的学号和姓名

select
    si.stu_id,
    si.stu_name
from score_info sc
join student_info si
on sc.stu_id = si.stu_id
where sc.course_id in
(
    select
        course_id
    from score_info
    where stu_id='001'    --001的课程
) and sc.stu_id <> '001'  --排除001学生
group by si.stu_id,si.stu_name;

4.2.10 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩

-- 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
select stu_name,course_name,sc.score,t1.avg_score from score_info sc
join student_info si
on sc.stu_id=si.stu_id
join course_info ci
on sc.course_id=ci.course_id
join(
select stu_id,avg(score) avg_score from score_info
group by stu_id,course_id)t1
on sc.stu_id=t1.stu_id
order by t1.avg_score desc;

总结

       本想着跳过这些题目的,但是最后还是刷了一遍,期间确实发现了很多基础的不足,总之这次刷题收获满满。

相关文章
|
2月前
|
SQL HIVE
【Hive SQL 每日一题】环比增长率、环比增长率、复合增长率
该文介绍了环比增长率、同比增长率和复合增长率的概念及计算公式,并提供了SQL代码示例来计算商品的月度增长率。环比增长率是相邻两期数据的增长率,同比增长率是与去年同期相比的增长率,复合增长率则是连续时间段内平均增长的速率。文章还包含了一组销售数据用于演示如何运用这些增长率进行计算。
|
22天前
|
SQL 分布式计算 关系型数据库
Hadoop-12-Hive 基本介绍 下载安装配置 MariaDB安装 3台云服务Hadoop集群 架构图 对比SQL HQL
Hadoop-12-Hive 基本介绍 下载安装配置 MariaDB安装 3台云服务Hadoop集群 架构图 对比SQL HQL
27 2
|
11天前
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用问题之如何使用Flink SQL连接带有Kerberos认证的Hive
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
29天前
|
SQL 存储 数据库
技术好文:SQL查询语句基本练习
技术好文:SQL查询语句基本练习
|
2月前
|
SQL HIVE
【Hive SQL】字符串操作函数你真的会用吗?
本文介绍了SQL中判断字符串是否包含子串的几种方法。`IN`函数判断元素是否完全等于给定元素组中的某项,而非包含关系。`INSTR`和`LOCATE`函数返回子串在字符串中首次出现的位置,用于检测是否存在子串。`SUBSTR`则用于提取字符串的子串。`LIKE`用于模糊匹配,常与通配符配合使用。注意`IN`并非用于判断子串包含。
|
2月前
|
SQL HIVE
【Hive SQL 每日一题】统计用户连续下单的日期区间
该SQL代码用于统计用户连续下单的日期区间。首先按`user_id`和`order_date`分组并去除重复,然后使用`row_number()`标记行号,并通过`date_sub`与行号计算潜在的连续日期。接着按用户ID和计算后的日期分组,排除连续订单数少于2的情况,最后提取连续下单的起始和结束日期。输出结果展示了用户连续下单的日期范围。
|
2月前
|
SQL 关系型数据库 HIVE
【Hive SQL 每日一题】统计最近1天/7天/30天商品的销量
这段内容是关于SQL查询的示例,目标是统计`sales`表中最近1天、7天和30天的商品销量和销售次数。表结构包含`id`、`product_id`、`quantity`和`sale_date`字段。初始查询方法通过三个独立的子查询完成,但效率较低。优化后的查询使用了`lateral view explode`将数据炸裂,通过一次查询同时获取所有所需时间段的数据,提高了效率。示例中展示了优化前后的SQL代码及结果对比。
|
2月前
|
SQL HIVE
【Hive SQL 每日一题】统计最近7天内连续下单3日的用户量
创建了一个名为`sales`的测试表,包含`user_id`、`product_id`、`quantity`和`sale_date`字段,插入了多条销售数据。需求是找出最近7天内连续下单3天的用户数量。SQL查询通过分组和窗口函数`row_number()`检查日期连续性,最终计算满足条件的唯一用户数。示例结果显示有3名用户符合条件。
|
2月前
|
SQL 数据采集 数据挖掘
大数据行业应用之Hive数据分析航班线路相关的各项指标
大数据行业应用之Hive数据分析航班线路相关的各项指标
144 1
|
12天前
|
SQL 分布式计算 大数据
大数据处理平台Hive详解
【7月更文挑战第15天】Hive作为基于Hadoop的数据仓库工具,在大数据处理和分析领域发挥着重要作用。通过提供类SQL的查询语言,Hive降低了数据处理的门槛,使得具有SQL背景的开发者可以轻松地处理大规模数据。然而,Hive也存在查询延迟高、表达能力有限等缺点,需要在实际应用中根据具体场景和需求进行选择和优化。