mysql sql面试题 sql经典习题 sql练习题

目录

    • 读我
    • 数据&建表语句(MySQL)
    • student
    • score
    • teacher
    • course
    • 以下所有题目解题思路
    • ---> 查询学生各科成绩并显示排名
    • ---> 查询各科成绩的第2名到第3名的学生信息及该课程成绩
    • ---> 查询学生总成绩并进行排名
    • ---> 查询学生总成绩的前3名
    • ---> 查询学生总成绩的第2名到第3名
    • ---> 查询学生各科成绩及总成绩(总成绩要排名)
    • ---> 查询各科成绩最高分、最低分、平均分、及格率、良好率等
    • ---> 查询学生单科成绩,单科总成绩,以及每位同学的总成绩(排名),并在一张表中显示
    • ---> 查询和"01"号同学学习课程完全相同的其他同学的信息
    • ---> 查询和"01"号同学学习课程不完全相同的其他同学的信息
    • ---> 查询没有学全所有课程的同学的信息
    • ---> 查询学过"张三"老师授课的同学的信息
    • ---> 查询没学过"张三"老师讲授的任一门课程的学生姓名
    • ---> 查询各科成绩都大于4号同学的学号
    • ---> 查询"01"课程比"02"课程成绩高的学生的信息及课程分数
    • ---> 查询每一门课程都大于60分的同学
    • ---> 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
    • ---> 查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息
    • ---> 查询学过编号"01"但是没有学过编号"02"的课程的同学的信息
    • ---> 查询"李"姓老师的数量
    • ---> 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
    • ---> 查询不同老师所教课程的平均成绩(平均成绩从高到低显示,平均成绩相同时,按课程编号升序排列)
    • ---> 查询所有课程成绩的第2名到第3名的学生信息及该课程成绩
    • ---> 查询选修"张三"老师所授课程的学生中,成绩最高的学生信息,所学课程名称以及成绩
    • ---> 查询选修"张三"老师所授课程的学生中,成绩最高的学生姓名,成绩,以及其它课程的成绩
    • ---> 查询1990年出生的学生名单
    • ---> 查询各学生的年龄
    • ---> 查询本周过生日的学生
    • ---> 查询下周过生日的学生
    • --->查询12月份过生日的学生
    • 总结:mysql8.x语法更为严格体现在哪些方面
    • ---> 数据&建表语句(hive)
    • sql 面试题-求职

读我

网上很多这样的题目,好像一共50道,但是其中有的题目的解法是错误的。题目用了一题多解(多解思路必须要掌握)

bug:score这张表当中没有成绩的同学不显示

mysql 高版本支持了窗口函数,并且对group by 等语法要求更加严格

# 查看mysql版本
select VERSION();
# 8.0.31

数据&建表语句(MySQL)

create database test1;
use test1;
create table student
(
    s_id    varchar(10),
    s_name  varchar(10),
    s_birth datetime,
    s_sex   varchar(10)
);

insert into student (s_id, s_name, s_birth, s_sex) values ('01', '赵雷', '1990-01-01 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('02', '钱电', '1990-12-21 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('03', '孙风', '1990-05-20 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('04', '李云', '1990-08-06 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('05', '周梅', '1991-12-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('06', '吴兰', '1992-03-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('07', '郑竹', '1989-07-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('08', '王菊', '1990-01-20 00:00:00', '女');


create table score
(
    s_id    varchar(10),
    c_id    varchar(10),
    s_score decimal(18, 1)
);

insert into score (s_id, c_id, s_score) values ('01', '01', 80.0);
insert into score (s_id, c_id, s_score) values ('01', '02', 90.0);
insert into score (s_id, c_id, s_score) values ('01', '03', 99.0);
insert into score (s_id, c_id, s_score) values ('02', '01', 70.0);
insert into score (s_id, c_id, s_score) values ('02', '02', 60.0);
insert into score (s_id, c_id, s_score) values ('02', '03', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '01', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '02', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '03', 80.0);
insert into score (s_id, c_id, s_score) values ('04', '01', 50.0);
insert into score (s_id, c_id, s_score) values ('04', '02', 30.0);
insert into score (s_id, c_id, s_score) values ('04', '03', 20.0);
insert into score (s_id, c_id, s_score) values ('05', '01', 76.0);
insert into score (s_id, c_id, s_score) values ('05', '02', 87.0);
insert into score (s_id, c_id, s_score) values ('06', '01', 31.0);
insert into score (s_id, c_id, s_score) values ('06', '03', 34.0);
insert into score (s_id, c_id, s_score) values ('07', '02', 89.0);
insert into score (s_id, c_id, s_score) values ('07', '03', 98.0);


create table course
(
    c_id   varchar(10),
    c_name varchar(10),
    t_id   varchar(10)
);

insert into course (c_id, c_name, t_id) values ('01', '语文', '02');
insert into course (c_id, c_name, t_id) values ('02', '数学', '01');
insert into course (c_id, c_name, t_id) values ('03', '英语', '03');


create table teacher
(
    t_id   varchar(10),
    t_name varchar(10)
);

insert into teacher (t_id, t_name) values ('01', '张三');
insert into teacher (t_id, t_name) values ('02', '李四');
insert into teacher (t_id, t_name) values ('03', '王五');


student

mysql sql面试题 sql经典习题 sql练习题_第1张图片

score

bug:score这张表当中没有成绩的不显示

(正确的做法:没有参加考试的同学成绩直接显示为0,而不是不显示),这样会导致问题。后来我在发现问题后,也不想再去修改这张表的数据了,因为太懒

mysql sql面试题 sql经典习题 sql练习题_第2张图片

teacher

mysql sql面试题 sql经典习题 sql练习题_第3张图片

course

mysql sql面试题 sql经典习题 sql练习题_第4张图片

以下所有题目解题思路

mysql sql面试题 sql经典习题 sql练习题_第5张图片
旁人务下载-解题思路文档

—> 查询学生各科成绩并显示排名

典型的分组TopN的弱化题目

select st.s_id,
       st.s_name,
       c.c_name,
       sc.s_score,
       row_number() over (partition by sc.c_id order by sc.s_score desc ) as ranking
from score sc
         join student st on st.s_id = sc.s_id
         join course c on sc.c_id = c.c_id;
s_id s_name c_name s_score ranking
01 赵雷 语文 80.0 1
03 孙风 语文 80.0 2
05 周梅 语文 76.0 3
02 钱电 语文 70.0 4
04 李云 语文 50.0 5
06 吴兰 语文 31.0 6
01 赵雷 数学 90.0 1
07 郑竹 数学 89.0 2
05 周梅 数学 87.0 3
03 孙风 数学 80.0 4
02 钱电 数学 60.0 5
04 李云 数学 30.0 6
01 赵雷 英语 99.0 1
07 郑竹 英语 98.0 2
03 孙风 英语 80.0 3
02 钱电 英语 80.0 4
06 吴兰 英语 34.0 5
04 李云 英语 20.0 6

bug:无成绩的没有排名(因为score这张表没有成绩的都不显示)

—> 查询各科成绩的第2名到第3名的学生信息及该课程成绩

select *
from (select st.s_id,
             st.s_name,
             c.c_name,
             sc.s_score,
             row_number() over (partition by sc.c_id order by sc.s_score desc ) as ranking
      from score sc
               join student st on st.s_id = sc.s_id
               join course c on sc.c_id = c.c_id) t1
where t1.ranking >= 2
  and ranking <= 3;
s_id s_name c_name s_score ranking
03 孙风 语文 80.0 2
05 周梅 语文 76.0 3
07 郑竹 数学 89.0 2
05 周梅 数学 87.0 3
07 郑竹 英语 98.0 2
02 钱电 英语 80.0 3

—> 查询学生总成绩并进行排名

select st.s_id,
       st.s_name,
       sum(sc.s_score)                                    as sumScore,
       row_number() over (order by sum(sc.s_score) desc ) as ranking
from score sc
         join student st on st.s_id = sc.s_id
         join course c on sc.c_id = c.c_id
group by st.s_id, st.s_name;
s_id s_name sumscore ranking
01 赵雷 269.0 1
03 孙风 240.0 2
02 钱电 210.0 3
07 郑竹 187.0 4
05 周梅 163.0 5
04 李云 100.0 6
06 吴兰 65.0 7

bug:score这张表当中没有成绩的都不显示,导致王菊没有显示出来

—> 查询学生总成绩的前3名

会了下边的题目,求TopN就非常简单

—> 查询学生总成绩的第2名到第3名

这里的方法2有局限性

-- 方法1
select *
from (select st.s_id,
             st.s_name,
             sum(sc.s_score)                                    as sumScore,
             row_number() over (order by sum(sc.s_score) desc ) as ranking
      from score sc
               join student st on st.s_id = sc.s_id
               join course c on sc.c_id = c.c_id
      group by st.s_id, st.s_name) t1
where t1.ranking >= 2
  and t1.ranking <= 3;


-- 方法2 
select st.s_id,
       st.s_name,
       sum(sc.s_score)                                    as sumScore,
       row_number() over (order by sum(sc.s_score) desc ) as ranking
from score sc
         join student st on st.s_id = sc.s_id
         join course c on sc.c_id = c.c_id
group by st.s_id, st.s_name
limit 1,2;
s_id s_name sumscore ranking
03 孙风 240.0 2
02 钱电 210.0 3

—> 查询学生各科成绩及总成绩(总成绩要排名)

这里的2种解法都很重要

解法1

select st.s_id,
       st.s_name,
       sum(case when c.c_name = '语文' then sc.s_score else 0 end) as chinese,
       sum(case when c.c_name = '数学' then sc.s_score else 0 end) as math,
       sum(case when c.c_name = '英语' then sc.s_score else 0 end) as english,
       sum(sc.s_score)                                           as sumScore,
       row_number() over (order by sum(sc.s_score) desc )        as ranking
from score sc
         join course c on sc.c_id = c.c_id
         join student st on st.s_id = sc.s_id
group by st.s_id, st.s_name;


# case when 可以用 if 来简化
sum(case when c.c_name = '语文' then sc.s_score else 0 end)<=>sum(if(c.c_name = '语文', sc.s_score, 0))
s_id s_name chinese math english sumScore ranking
01 赵雷 80.0 90.0 99.0 269.0 1
03 孙风 80.0 80.0 80.0 240.0 2
02 钱电 70.0 60.0 80.0 210.0 3
07 郑竹 0.0 89.0 98.0 187.0 4
05 周梅 76.0 87.0 0.0 163.0 5
04 李云 50.0 30.0 20.0 100.0 6
06 吴兰 31.0 0.0 34.0 65.0 7

解法2

select t0.s_id,
       t0.s_name,
       ifnull(t1.chinese, 0),
       ifnull(t2.math, 0),
       ifnull(t3.english, 0),
       t0.sumScore,
       t0.ranking
from (select st.s_id,
             st.s_name,
             sum(sc.s_score)                                    as sumScore,
             row_number() over (order by sum(sc.s_score) desc ) as ranking
      from score sc
               join student st on sc.s_id = st.s_id
      group by st.s_id, st.s_name) t0
         left join (select sc.s_id,
                           sc.s_score as chinese
                    from score sc
                             join course c on sc.c_id = c.c_id and c.c_name = '语文') t1 on t0.s_id = t1.s_id
         left join (select sc.s_id,
                           sc.s_score as math
                    from score sc
                             join course c on sc.c_id = c.c_id and c.c_name = '数学') t2 on t0.s_id = t2.s_id
         left join (select sc.s_id,
                           sc.s_score as english
                    from score sc
                             join course c on sc.c_id = c.c_id and c.c_name = '英语') t3
                   on t0.s_id = t3.s_id;

—> 查询各科成绩最高分、最低分、平均分、及格率、良好率等

格式要求:显示课程ID,课程name,最高分,最低分,平均分,及格率,良好率

评级标准:及格为>=60,良好为:[60,80]

select c.c_id,
       c.c_name,
       max(sc.s_score)                                                                                   as maxScore,
       min(sc.s_score)                                                                                   as minScore,
       round(avg(sc.s_score), 2)                                                                         as avgScore,
       # count+if
       # count时,必须用null,不能用0,因为0所在也被计数,null则不被计数
       round(count(if(sc.s_score >= 60, 1, null)) / count(sc.s_id), 2)                                   as passRate,
       # sum+case when
       round(sum(case when sc.s_score >= 60 and sc.s_score <= 80 then 1 else 0 end) / count(sc.s_id), 2) as goodRate
from score sc
         join course c on sc.c_id = c.c_id
group by c.c_id, c.c_name;
c_id c_name maxScore minScore avgScore passRate goodRate
01 语文 80.0 31.0 64.50 0.67 0.67
02 数学 90.0 30.0 72.67 0.83 0.33
03 英语 99.0 20.0 68.50 0.67 0.33

—> 查询学生单科成绩,单科总成绩,以及每位同学的总成绩(排名),并在一张表中显示

select st.s_id,
       st.s_name,
       sum(case when c.c_name = '语文' then sc.s_score else 0 end) as chinese,
       sum(case when c.c_name = '数学' then sc.s_score else 0 end) as math,
       sum(case when c.c_name = '英语' then sc.s_score else 0 end) as english,
       sum(sc.s_score)                                           as sumScore,
       row_number() over (order by sum(sc.s_score) desc )        as ranking
from score sc
         join course c on sc.c_id = c.c_id
         join student st on st.s_id = sc.s_id
group by st.s_id, st.s_name
union all
select '单科总成绩', # 将整个表看成一组
       '',
       sum(t1.chinese),
       sum(t1.math),
       sum(t1.english),
       '',
       ''
from (select st.s_id,
             st.s_name,
             sum(case when c.c_name = '语文' then sc.s_score else 0 end) as chinese,
             sum(case when c.c_name = '数学' then sc.s_score else 0 end) as math,
             sum(case when c.c_name = '英语' then sc.s_score else 0 end) as english
      from score sc
               join course c on sc.c_id = c.c_id
               join student st on st.s_id = sc.s_id
      group by st.s_id, st.s_name) t1;
s_id s_name chinese math english sumScore ranking
01 赵雷 80.0 90.0 99.0 269.0 1
03 孙风 80.0 80.0 80.0 240.0 2
02 钱电 70.0 60.0 80.0 210.0 3
07 郑竹 0.0 89.0 98.0 187.0 4
05 周梅 76.0 87.0 0.0 163.0 5
04 李云 50.0 30.0 20.0 100.0 6
06 吴兰 31.0 0.0 34.0 65.0 7
单科总成绩 387.0 436.0 411.0

—> 查询和"01"号同学学习课程完全相同的其他同学的信息

select *
from student
where s_id in (select s_id
               from score
               where s_id != '01'
               group by s_id
               having group_concat(distinct c_id order by c_id separator '|') =
                      (select group_concat(distinct c_id order by c_id separator '|')
                       from score
                       where s_id = '01'));

-- 方法2 join 
select *
from student
where s_id in (select s_id
               from (select s_id,
                            group_concat(distinct c_id order by c_id separator '|') as a
                     from score
                     where s_id != '01'
                     group by s_id) t1
                        join (select group_concat(distinct c_id order by c_id separator '|') as b
                              from score
                              where s_id = '01') t2
                             on t1.a = t2.b);

-- 方法3 join 
select st.*
from (select s_id,
             group_concat(distinct c_id order by c_id separator '|') as a
      from score
      where s_id != '01'
      group by s_id) t1
         join (select group_concat(distinct c_id order by c_id separator '|') as b
               from score
               where s_id = '01') t2
              on t1.a = t2.b
         join student st on st.s_id = t1.s_id;
s_id s_name s_birth s_sex
02 钱电 1990-12-21 00:00:00
03 孙风 1990-05-20 00:00:00
04 李云 1990-08-06 00:00:00

以下必须是HQL语法规则

select *
from student
         join (select s_id
               from (select s_id,
                            concat_ws('|', collect_set(c_id)) as num1
                     from score
                     where s_id <> '01'
                     group by s_id) t1
                        join(select concat_ws('|', collect_set(c_id)) as num2
                             from score
                             where s_id = '01') t2
                            on t1.num1 = t2.num2) t3
              on student.s_id = t3.s_id;

—> 查询和"01"号同学学习课程不完全相同的其他同学的信息

-- 方法1
select *
from student
where s_id in (select s_id
               from (select s_id,
                            group_concat(distinct c_id order by c_id separator '|') as a
                     from score
                     where s_id != '01'
                     group by s_id) t1
                        left join (select group_concat(distinct c_id order by c_id separator '|') as b
                                   from score
                                   where s_id = '01') t2
                                  on t1.a = t2.b
               where t2.b is null);

-- 方法2(适用于hive)
select student.s_id, student.s_name
from student
         join (select *
               from (select s_id, concat_ws('|', collect_set(c_id)) as num1
                     from score
                     group by s_id
                     having s_id <> '01') t1 -- <>等价于!=
                        left join (select concat_ws('|', collect_set(c_id)) as num2
                                   from score
                                   where s_id = '01'
               ) t2 on t1.num1 = t2.num2
               where t2.num2 is null) t3
              on t3.s_id = student.s_id;
            
-- answer3 
可以使用上面提到过的 group_concat
s_id s_name s_birth s_sex
5 周梅 1991-12-01 00:00:00
6 吴兰 1992-03-01 00:00:00
7 郑竹 1989-07-01 00:00:00
8 王菊 1990-01-20 00:00:00

—> 查询没有学全所有课程的同学的信息

别处有引用,勿动!!!

-- answer 2
select *
from student
where s_id in (select s_id
               from score
               group by s_id
               having count(distinct c_id) < (select count(distinct c_id) from course));

-- answer 3
select student.*
from student
where s_id in (select s_id
               from (select s_id,
                            count(distinct c_id) as num1
                     from score
                     group by s_id) t1
                        left join(select count(distinct c_id) as num2
                                  from course) t2
                                 on t1.num1 = t2.num2
               where t2.num2 is null);
s_id s_name s_birth s_sex
05 周梅 1991-12-01
06 吴兰 1992-03-01
07 郑竹 1989-07-01
08 王菊 1990-01-20

hive中如果使用concat_ws(‘|’, collect_set(c_id),需要注意的事项

select concat_ws('|', collect_set(c_id)) as num2
from course;
num2
03|01|02
select s_id, concat_ws('|', collect_set(c_id)) as num1
from score
group by s_id;
s_id num1
01 01|02|03
02 01|02|03
03 01|02|03
04 01|02|03
05 01|02
06 01|03
07 02|03
select *
from (select s_id, concat_ws('|', collect_set(c_id)) as num1
      from score
      group by s_id) t1
         join (select concat_ws('|', collect_set(c_id)) as num2
               from course) t2
on t1.num1 = t2.num2;

mysql sql面试题 sql经典习题 sql练习题_第6张图片
在这里插入图片描述
总结:num1的数据集和num2的数据集最好来自同一张表

s_id s_name s_birth s_sex
02 钱电 1990-12-21 00:00:00
03 孙风 1990-05-20 00:00:00
04 李云 1990-08-06 00:00:00
05 周梅 1991-12-01 00:00:00
06 吴兰 1992-03-01 00:00:00
07 郑竹 1989-07-01 00:00:00

—> 查询学过"张三"老师授课的同学的信息

直接关联查询

--  直接关联查询
select student.*,teacher.t_name
from student
         join score on student.s_id = score.s_id
         join course on course.c_id = score.c_id
         join teacher on course.t_id = teacher.t_id and t_name = '张三';
s_id s_name s_birth s_sex t_name
01 赵雷 1990-01-01 00:00:00 张三
02 钱电 1990-12-21 00:00:00 张三
03 孙风 1990-05-20 00:00:00 张三
04 李云 1990-08-06 00:00:00 张三
05 周梅 1991-12-01 00:00:00 张三
07 郑竹 1989-07-01 00:00:00 张三

—> 查询没学过"张三"老师讲授的任一门课程的学生姓名

select student.*
from student
where s_id not in (select s_id
                   from score
                            join course on score.c_id = course.c_id
                            join teacher on teacher.t_id = course.t_id and t_name = '张三');
select student.*
from student
         left join (select s_id
                    from score
                             join course on score.c_id = course.c_id
                             join teacher on teacher.t_id = course.t_id and t_name = '张三') t1
                   on student.s_id = t1.s_id
where t1.s_id is null;
s_id s_name s_birth s_sex
06 吴兰 1992-03-01 00:00:00
08 王菊 2017-01-20 00:00:00

—> 查询各科成绩都大于4号同学的学号

select t1.*
from (select s_id,
             sum(case when score.c_id = '01' then score.s_score else 0 end) as chinese,
             sum(case when score.c_id = '02' then score.s_score else 0 end) as math,
             sum(case when score.c_id = '03' then score.s_score else 0 end) as english
      from score
      group by s_id) t1
         join (select sum(case when score.c_id = '01' then score.s_score else 0 end) as chinese,
                      sum(case when score.c_id = '02' then score.s_score else 0 end) as math,
                      sum(case when score.c_id = '03' then score.s_score else 0 end) as english
               from score
               where score.s_id = '04') t2
where t1.chinese > t2.chinese
  and t1.math > t2.math
  and t1.english > t2.english;
s_id chinese math english
4 50.0 30.0 20.0
s_id chinese math english
1 80.0 90.0 99.0
2 70.0 60.0 80.0
3 80.0 80.0 80.0

—> 查询"01"课程比"02"课程成绩高的学生的信息及课程分数

方法1

select student.s_id,
       student.s_name,
       student.s_sex,
       sum(if(c_id = '01', s_score, 0)) as c01_score,
       sum(if(c_id = '02', s_score, 0)) as c02_score
from score
         join student on score.s_id = student.s_id
group by student.s_id, student.s_name, student.s_sex
having c01_score > c02_score;
s_id s_name s_sex c01_score c02_score
02 钱电 70.0 60.0
04 李云 50.0 30.0
06 吴兰 31.0 0.0

方法2

select student.s_id,
       student.s_name,
       t3.c01_score,
       t3.c02_score
from student
         join (select t1.s_id, t1.c01_score, t2.c02_score
               from (select s_id, s_score as c01_score
                     from score
                     where c_id = '01') t1
                        join
                    (select s_id, s_score as c02_score
                     from score
                     where c_id = '02') t2
                    on t1.s_id = t2.s_id
               where t1.c01_score > t2.c02_score) t3
              on student.s_id = t3.s_id;
s_id s_name s_sex c01_score c02_score
02 钱电 70.0 60.0
04 李云 50.0 30.0

寄语:2种方法都很重要

—> 查询每一门课程都大于60分的同学

select s_id,
       s_name
from student
where s_id in (select s_id
               from score
               group by s_id
               having min(s_score) > 60
);
s_id s_name
01 赵雷
03 孙风
05 周梅
07 郑竹

—> 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩

数据&建表

create table score_cross
(
    s_id    string,
    c_id    string,
    s_score int
)

insert overwrite table score_cross
values ('01', '01', 80),
       ('01', '02', 100),
       ('01', '03', 100),
       ('02', '02', 80),
       ('03', '02', 80);
s_id c_id s_score
01 01 80
01 02 100
01 03 100
02 02 80
03 02 80

无任何连接条件,产生了笛卡尔集合

select *
from score_cross s1, score_cross s2
where s1.c_id<>s2.c_id and s1.s_score=s2.s_score
s_id c_id s_score s_id c_id s_score
01 01 80 03 02 80
01 01 80 02 02 80
01 02 100 01 03 100
01 03 100 01 02 100
02 02 80 01 01 80
03 02 80 01 01 80

去重

select distinct s1.*
from score_cross s1, score_cross s2
where s1.c_id<>s2.c_id and s1.s_score=s2.s_score
s_id c_id s_score
02 02 80
01 01 80
01 02 100
01 03 100
03 02 80

—> 查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息

select st.*
from (select s_id from score where c_id = '01') t1
         join (select s_id from score where c_id = '02') t2
              on t1.s_id = t2.s_id
         join student st on st.s_id = t1.s_id;
s_id s_name s_birth s_sex
01 赵雷 1990-01-01 00:00:00
02 钱电 1990-12-21 00:00:00
03 孙风 1990-05-20 00:00:00
04 李云 1990-08-06 00:00:00
05 周梅 1991-12-01 00:00:00

另一解题思路:用 in

select student.*
from student
where s_id in (select s_id from score where c_id = '01' and s_id in (select s_id from score where c_id = '02'));

—> 查询学过编号"01"但是没有学过编号"02"的课程的同学的信息

select st.*
from (select s_id from score where c_id = '01') t1
         left join (select s_id from score where c_id = '02') t2 on t1.s_id = t2.s_id
         left join student st on t1.s_id = st.s_id
where t2.s_id is null;
s_id s_name s_birth s_sex
06 吴兰 1992-03-01 00:00:00

另一解题思路:用 not in

不管是mysql中,还是hive中,都不建议使用 not in

select st.*
from score sc
         join student st on sc.s_id = st.s_id
where sc.c_id = '01'
  and sc.s_id  not in (select s_id
                       from score
                       where c_id = '02');

—> 查询"李"姓老师的数量

select count(1)
from teacher
where t_name like "李%";

res:1

—> 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩

错误做法:

select s_id, round(avg(s_score), 2) as avgscore
from score
where s_score < 60
group by s_id
having count(s_id) >= 2
s_id avgscore
04 33.33
06 32.50

以上方法是错误的,它只把两门及其以上不及格课程的同学的学号给筛选出来了,但是平均成绩的计算方式是错误的

原表中6号同学只有2门成绩,并且都不及格

在这里插入图片描述

添加6号同学的2号课程为85分

mysql sql面试题 sql经典习题 sql练习题_第7张图片
执行上述语句

mysql sql面试题 sql经典习题 sql练习题_第8张图片

正确做法:

select st.s_id,
       st.s_name,
       round(avg(sc.s_score), 2) as avgScore
from score sc
         join (select s_id
               from score
               where s_score < 60
               group by s_id
               having count(1) >= 2) t1 on sc.s_id = t1.s_id
         join student st on st.s_id = t1.s_id
group by st.s_id, st.s_name;
s_id s_name avgscore
04 李云 33.33333
06 吴兰 50.00000

—> 查询不同老师所教课程的平均成绩(平均成绩从高到低显示,平均成绩相同时,按课程编号升序排列)

order by 中被排序的字段,must be either aggregated, or mentioned in GROUP BY clause

具体解释:

avgScore是被聚合函数应用的字段
c_id 是被分组的字段

select t.t_name,
       c.c_name,
       round(avg(sc.s_score), 2) as avgScore
from score sc
         join course c on sc.c_id = c.c_id
         join teacher t on c.t_id = t.t_id
group by t.t_name, c.c_name, c.c_id
order by avgScore desc, c.c_id asc;
c_name t_name avgscore
数学 张三 72.67
英语 王五 68.50
语文 李四 64.50

—> 查询所有课程成绩的第2名到第3名的学生信息及该课程成绩

上边已经出现过这样类型的题目了,但是这里又出现了,出现的目的是为了告知,数据排序时,如果选择join的方式不对,那么可能无序。例如你把 left join 换成 join 可以试试

select t1.s_id,
       c_name,
       t1.s_score,
       t1.ranking
from (select s_id,
             c_id,
             s_score,
             row_number() over (partition by c_id order by s_score desc ) as ranking
      from score) t1
         left join student st on st.s_id = t1.s_id
         left join course c on c.c_id = t1.c_id
where t1.ranking >= 2
  and t1.ranking <= 3;
s_id c_name s_score ranking
03 语文 80.0 2
05 语文 76.0 3
07 数学 89.0 2
05 数学 87.0 3
07 英语 98.0 2
03 英语 80.0 3

—> 查询选修"张三"老师所授课程的学生中,成绩最高的学生信息,所学课程名称以及成绩

mysql8.x系列语法更为严格,以下语句会报错: sql_mode=only_full_group_by

它要求:某字段使用聚合函数后,必须同时使用group by

select student.*,
       course.c_name,
       max(score.s_score) as maxscore
from student
         join score on student.s_id = score.s_id
         join course on score.c_id = course.c_id
         join teacher on teacher.t_id = course.t_id and t_name = '张三';
s_id s_name s_birth s_sex c_name maxscore
01 赵雷 1990-01-01 00:00:00 数学 90.0

—> 查询选修"张三"老师所授课程的学生中,成绩最高的学生姓名,成绩,以及其它课程的成绩

mysql8.x系列语法更为严格,以下语句会报错: sql_mode=only_full_group_by

select student.s_name,
       t1.mathmaxscore,
       sum(case when score.c_id = '01' then score.s_score else 0 end) as chinese,
       sum(case when score.c_id = '03' then score.s_score else 0 end) as english
from score
         join (select s_id,
                      max(s_score) as mathmaxscore
               from score
                        join course on score.c_id = course.c_id
                        join teacher on teacher.t_id = course.t_id and teacher.t_name = '张三') t1
              on score.s_id = t1.s_id
         join student on student.s_id = score.s_id;

之所以不用in,是因为用了以后无法确定那门课是最高成绩,故:用join比较合适

s_name mathmaxscore chinese english
赵雷 90.0 80.0 99.0

—> 查询1990年出生的学生名单

select *
from student
where s_birth like '1990%';
s_id s_name s_birth s_sex
01 赵雷 1990-01-01
02 钱电 1990-12-21
03 孙风 1990-05-20
04 李云 1990-08-06
08 王菊 1990-01-20

—> 查询各学生的年龄

-- 张三生日:2020-05-04
-- 李四生日:2020-03-04
-- 当前日期:2022-04-04
-- 通常计算年龄的方式(张三,李四) 2022-2020 = 2岁
select s_name, s_birth, year(current_date) - year(s_birth) as age
from student;
s_name s_birth age
赵雷 1990-01-01 00:00:00 32
钱电 1990-12-21 00:00:00 32
孙风 1990-05-20 00:00:00 32
李云 1990-08-06 00:00:00 32
周梅 1991-12-01 00:00:00 31
吴兰 1992-03-01 00:00:00 30
郑竹 1989-07-01 00:00:00 33
王菊 1990-01-20 00:00:00 32
-- 有时候较真计算年龄:张三实际年龄2岁少1个月:2022-2020-1=1岁
--                   李四实际年龄2岁多1个月:2022-2020-0=2岁
select s_name,
       s_birth,
       (year(current_date) - year(s_birth) - (case
                                                  when month(CURRENT_DATE) < month(s_birth) then 1
                                                  when month(CURRENT_DATE) = month(s_birth) and
                                                       day(CURRENT_DATE) < day(s_birth) then 1
                                                  else 0 end)
           ) as age
from student;
s_name s_birth age
赵雷 1990-01-01 00:00:00 32
钱电 1990-12-21 00:00:00 31
孙风 1990-05-20 00:00:00 32
李云 1990-08-06 00:00:00 32
周梅 1991-12-01 00:00:00 30
吴兰 1992-03-01 00:00:00 30
郑竹 1989-07-01 00:00:00 33
王菊 1990-01-20 00:00:00 32

—> 查询本周过生日的学生

select *
from student
where weekofyear(current_date) = weekofyear(s_birth);

—> 查询下周过生日的学生

select *
from student
where weekofyear(CURRENT_DATE) + 1 = weekofyear(s_birth);

—>查询12月份过生日的学生

--方法1
select s_name, s_sex, s_birth
from student
where substring(s_birth, 6, 2) = '12';

--方法2
select s_name, s_sex, s_birth
from student
where month(s_birth) = '12';
s_name s_sex s_birth
钱电 1990-12-21
周梅 1991-12-01

总结:mysql8.x语法更为严格体现在哪些方面

  1. order by 中被排序的字段,must be either aggregated, or mentioned in GROUP BY clause (例如查询不同老师所教课程的平均成绩)
  2. having 同 order by 一样
  3. 某字段使用聚合函数后,必须同时使用 group by(在student中,筛选出id最大的同学的名字)

—> 数据&建表语句(hive)

create table student
(
    s_id    string,
    s_name  string,
    s_birth string,
    s_sex   string
);

create table course
(
    c_id   string,
    c_name string,
    t_id   string
);

create table teacher
(
    t_id   string,
    t_name string
);

create table score
(
    s_id    string,
    c_id    string,
    s_score int
);


insert into student (s_id, s_name, s_birth, s_sex) values ('01', '赵雷', '1990-01-01 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('02', '钱电', '1990-12-21 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('03', '孙风', '1990-05-20 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('04', '李云', '1990-08-06 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('05', '周梅', '1991-12-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('06', '吴兰', '1992-03-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('07', '郑竹', '1989-07-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('08', '王菊', '1990-01-20 00:00:00', '女');

insert into score (s_id, c_id, s_score) values ('01', '01', 80.0);
insert into score (s_id, c_id, s_score) values ('01', '02', 90.0);
insert into score (s_id, c_id, s_score) values ('01', '03', 99.0);
insert into score (s_id, c_id, s_score) values ('02', '01', 70.0);
insert into score (s_id, c_id, s_score) values ('02', '02', 60.0);
insert into score (s_id, c_id, s_score) values ('02', '03', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '01', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '02', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '03', 80.0);
insert into score (s_id, c_id, s_score) values ('04', '01', 50.0);
insert into score (s_id, c_id, s_score) values ('04', '02', 30.0);
insert into score (s_id, c_id, s_score) values ('04', '03', 20.0);
insert into score (s_id, c_id, s_score) values ('05', '01', 76.0);
insert into score (s_id, c_id, s_score) values ('05', '02', 87.0);
insert into score (s_id, c_id, s_score) values ('06', '01', 31.0);
insert into score (s_id, c_id, s_score) values ('06', '03', 34.0);
insert into score (s_id, c_id, s_score) values ('07', '02', 89.0);
insert into score (s_id, c_id, s_score) values ('07', '03', 98.0);

insert into course (c_id, c_name, t_id) values ('01', '语文', '02');
insert into course (c_id, c_name, t_id) values ('02', '数学', '01');
insert into course (c_id, c_name, t_id) values ('03', '英语', '03');


insert into teacher (t_id, t_name) values ('01', '张三');
insert into teacher (t_id, t_name) values ('02', '李四');
insert into teacher (t_id, t_name) values ('03', '王五');

sql 面试题-求职

sql 面试题-求职

你可能感兴趣的:(mysql-practice,mysql,1024程序员节)