如下是SQL面试必备的经典的50道题目,每道题都有博主本人的解题思路和对应的SQL语句。
每道题的思路与答案均为博主本人主观理解,仅供参考。面试
环境:MySQL8.0
可视化工具:Navicat函数
一、查询课程编号为01的课程比02的课程高的全部学生的学号和成绩
解题思路:
(1) 先把课程为01的学号和成绩找出来 as 表a
(2) 再把课程为02的学号和成绩找出来 as 表b
(3) 用inner join将表a和表b按照s_id链接起来
(4) 最后用where筛选表a成绩大于表b成绩的学生编号工具
select a.s_id from (select s_id,s_score from score where c_id='01') as a inner join (select s_id,s_score from score where c_id='02') as b on a.s_id=b.s_id where a.s_score>b.s_score;
二、查询平均成绩大于60分的学生的学号和平均成绩
解题思路:
(1) 先用group by对s_id进行分组
(2) 再用having过滤平均分大于60
tips:group by里的东西必须是select里的东西,除非是统计函数(avg,max等)code
select s_id,avg(s_score) from score group by s_id having avg(s_score)>60;
三、查询全部学生的学号、姓名、选课数、总成绩
解题思路:
(1) 姓名在student表,成绩在score表,所以须要链接两表;student表左链接score表,这样才能保证保留全部学生的信息
(2) 按s_id和s_score进行分组
(3) 选课数使用count(),总成绩使用sum(if(...))排序
select a.s_id, a.s_name, count(b.c_id), sum(if(b.s_score is null,0,b.s_score)) from student as a left join score as b on a.s_id=b.s_id group by a.s_id,a.s_name;
四、查询姓“猴”的老师的人数
解题思路:
(1) 使用like和%进行模糊查询
(2) 人数使用count()函数ip
select count(t_id) from teacher where t_name like '猴%';
五、查询没学过“张三”老师课的学生的学号、姓名
解题思路:
(1) 先找出学过"张三"老师可的学生,这些学生之外的学生就是没学过"张三"老师课的
(2) 在teacher表中获取"张三"的t_id,在course表中获取全部老师t_id和课程c_id,在score表中获取学生S_id和课程c_id
(3) teacher表与course表按t_id内链接,course表与score表按s_id内链接,而后选出学生s_id
(4) 最后从student表中中过滤不在上面的学生s_id数学
select s_id,s_name from student where s_id not in( select c.s_id from (select t_id from teacher where t_name='张三') as a inner join (select t_id, c_id from course) as b on a.t_id=b.t_id inner join (select s_id, c_id from score) as c on b.c_id=c.c_id );
六、查询学过“张三”老师所教的全部课的同窗的学号和姓名
解题思路:
(1) 首先查找"张三"教的全部课程c_id:将teahcer表和course表按t_id内链接
(2) 接着查找学过以上课程的学生:将student表和score表按s_id内链接
(3) 最后对s_id进行group by,过滤所选课程数量等于"张三"所教课程数量it
select a.s_id,a.s_name from student as a join score as b on a.s_id=b.s_id where b.c_id in ( -- (2)接着查找学过以上课程的学生:将student表和score表按s_id内链接 -- (1)首先查找"张三"教的全部课程c_id:将teahcer表和course表按t_id内链接 select b.c_id from teacher as a join course as b on a.t_id=b.t_id where a.t_name='张三' ) -- (3)最后对s_id进行group by,过滤所选课程数量等于"张三"所教课程数量 group by a.s_id having count(b.c_id)=( select count(b.c_id) from teacher as a join course as b on a.t_id=b.t_id where a.t_name='张三' );
七、查询学过编号为“01”的课程而且也学过编号为“02”的课程的学生的学号和姓名
解题思路:
(1) 查出学过编号01课程学生s_id做为表a
(2) 查找学过编号02课程学生s_id做为表b
(3) 将表a和表b内链接,选出学生编号s_id
(4) 最后从student表筛选学生编号包含以上s_id的学生io
select s_id,s_name from student where s_id in ( select a.s_id from (select s_id from score where c_id='01') as a join (select s_id from score where c_id='02') as b on a.s_id=b.s_id );
八、查询课程编号为“02”的总成绩可视化
select sum(s_score) from score group by c_id having c_id='02';
九、查询全部课程成绩小于60分的学生的学号和姓名
解题思路:
(1) 将score表按s_id进行group by,过滤条件为课程最大成绩小于60(若是最大成绩都小于60,那就意味全部成绩都小于60)
(2) 从student表中选出学生编号包含以上s_id的学生
select s_id,s_name from student where s_id in ( select s_id from score group by s_id having max(s_score)<60 );
十、查询没有学全全部课的学生的学号和姓名
解题思路:
(1) 首先从course表获取全部课程的总数
(2) 接着student表左链接score表并按student.s_id进行group by,过滤条件是每一个学生的课程数量小于第一步的课程总数
(3) 最后从student表中筛选出学生编号包含以上s_id的学生
tips:可能存在一门课也没有学的学生
select a.s_id,a.s_name from student as a left join score as b on a.s_id=b.s_id group by a.s_id having count(b.c_id)<( select count(c_id) from course );
十一、查询至少有一门课与学号为“01”的学生所学课程相同的学生的学号和姓名
解题思路:
(1) 查找出学号为"01"的学生所学课程编号c_id
(2) student表左链接score表,选出c_id有包含上面c_id的学生
(3) 接着对s_id进行group by,过滤s_id!=1,最后选择学生编号和姓名
select a.s_id,a.s_name from student as a left join score as b on a.s_id=b.s_id where b.c_id in ( select c_id from score where s_id='01' ) group by a.s_id having a.s_id<>'01';
12.查询和“01”号同窗所学课程彻底相同的其余同窗的学号
解题思路:
(1) 对score表按s_id进行group by,对每一个s_id的c_id进行group_concat转换,结果做为表a
(2) 查出"01"同窗所学课程编号c_id,并进行group_concat转换,结果做为表b,将表a与表b按照group_concat的结果进行内链接
(3) 以上结果就是与"01"同窗课程彻底相同的同窗(包括"01"),最后筛选学生编号不为"01"的
select a.s_id from (select s_id,group_concat(c_id order by c_id separator ',') as c_id_str from score group by s_id) as a inner join (select group_concat(c_id order by c_id separator ',') as c_id_str from score where s_id='01') as b on a.c_id_str=b.c_id_str where a.s_id<>'01';
1三、查询没学过“张三”老师讲授的任一门课程的学生姓名
解题思路:
(1) 查出"张三"的教师编号t_id as表a
(2) 表a按t_id内链接course表,course表再按c_id内链接score表,便选出学过"张三"课的学生编号s_id
(3) 最后student表中选出不包含上面编号的学生
select s_name from student where s_id not in ( select distinct c.s_id from (select t_id from teacher where t_name='张三') as a inner join (select t_id,c_id from course) as b on a.t_id=b.t_id inner join (select s_id,c_id from score) as c on b.c_id=c.c_id );
1四、查询有两门及以上课程不及格的同窗的学号、姓名和平均成绩
解题思路:
(1) 筛选score表中score小于60的记录,而后按s_id进行group by,过滤条件是课程数大于2,最后选出这些s_id
(2) 将上面结果做为表a内链接score表,score表按s_id内链接student表,如此一来便可得到有两门及其以上不及格课程同窗的信息
(3) 对以上联合表按s_id进行group by,计算每一个s_id的平均分
select a.s_id,c.s_name,avg(b.s_score) from (select s_id from score where s_score<60 group by s_id having count(c_id)>=2) as a inner join (select s_id,s_score from score) as b on a.s_id=b.s_id inner join (select s_id,s_name from student) as c on a.s_id=c.s_id group by a.s_id;
1五、检索“01”课程分数小于60、按分数降序排列的学生信息
解题思路:
(1) 从score表查找"01"课程分数小于60的学生编号s_id和"01"课程分数,并按按分数降序排序
(2)将上面结果做为表a与student表内链接,最后输出学生信息
select b.*,a.s_score from (select s_id,s_score from score where c_id='01' and s_score<60 order by s_score desc) as a inner join student as b on a.s_id=b.s_id;
1六、按平均成绩从高到低显示全部学生的全部课程的成绩以及平均成绩
解题思路:
(1) 将student表与score表左链接,能够获得学生信息与各科成绩
(2) 由于要按照平均成绩来排序,因此将第一步的链接表按s_id进行group by
(3) 最终显示格式为学生编号、学生姓名、01成绩、02成绩、03成绩、平均成绩,所以须要使用到case when语句
select a.s_id, a.s_name, -- 若是c_id是01,那么这一列显示01课程对应的成绩,不然为空 max(case when b.c_id='01' then b.s_score else null end) as '01', max(case when b.c_id='02' then b.s_score else null end) as '02', max(case when b.c_id='03' then b.s_score else null end) as '03', avg(b.s_score) as avg from (select s_id,s_name from student) as a left join (select s_id,c_id,s_score from score) as b on a.s_id=b.s_id group by a.s_id order by avg desc;
1七、查询各科成绩最高分、最低分和平均分:以以下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率(及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90)
解题思路:
(1) 显示列中有分数和课程名字,因此须要将score表与course表内链接
(2) 将上一步的链接表按课程编号c_id进行group by,分组后便可获取每一个课程的最高、低分和平均分
(3) 计算及格率中等率等须要使用case when
select a.c_id, a.c_name, max(b.s_score) as '最高分', min(b.s_score) as '最低分', avg(b.s_score) as '平均分', -- 若是成绩大于等于60就标记为1,不然标记为0,最后计算平均值就获得对应的合格率 avg(case when b.s_score>=60 then 1 else 0 end) as '及格率', avg(case when b.s_score>=70 and b.s_score<80 then 1 else 0 end) as '中等率', avg(case when b.s_score>=80 and b.s_score<90 then 1 else 0 end) as '优良率', avg(case when b.s_score>=90 then 1 else 0 end) as '优秀率' from course as a inner join score as b on a.c_id=b.c_id group by a.c_id;
1八、按各科成绩进行排序,并显示排名
解题思路:
(1) 由于须要显示排名,所以这里须要使用row_number()函数,类似的还有rank()和dense_rank()
(2) 分别显示课程编号、学生编号、课程成绩、排名
select c_id, s_id, s_score, row_number() over (partition by c_id order by s_score desc) as 'rank' from score;
1九、查询学生的总成绩并进行排名
解题思路:
(1) 将score表按学生编号s_id进行group by
(2) 使用row_number()对sum(s_score)进行排序
select s_id, sum(s_score) as sum_score, row_number() over(order by sum(s_score) desc) as 'rank' from score group by s_id;
20、查询不一样老师所教不一样课程的平均分并从高到低显示
解题思路:
(1) 不一样老师不一样课程的平均分:每一个老师教的每一门课的平均分
(2) 须要的字段有老师编号、课程编号、分数,所以须要将course表左链接score表
(3) 接着对老师编号和课程编号进行group by
(4) 输出老师编号、课程编号、分数,按avg(score.s_score)降序排列
select a.t_id, a.c_id, avg(b.s_score) from course as a left join score as b on a.c_id=b.c_id group by a.t_id,a.c_id order by avg(b.s_score) desc;
2一、查询全部课程的成绩第2名到第3名的学生信息及该课程成绩
解题思路:
(1) 须要有学生信息和课程成绩,所以须要链接student表和score表
(2) 使用row_number()函数按课程编号c_id分组并按成绩s_score降序排列
(3) 最后从上面的结果中筛选排名为第2名到第3名的记录
select * from ( select b.*, a.c_id, a.s_score, row_number() over(partition by a.c_id order by a.s_score desc) as 'rank' from score as a left join student as b on a.s_id=b.s_id ) as info where info.rank in (2,3);
2二、使用分段[100-85]、[85-70]、[70-60]、[<60]来统计各科成绩,分别统计各分数段人数、课程ID和课程名称
解题思路:
(1) 须要的字段有课程名称和分数,所以须要链接course表和score表
(2) 统计各科成绩分数段人数,因此要先对课程编号进行group by
(3) 接着就要使用sum()函数和case when来进行分段
tips:也可使用count(),可是count中else后面得是null不能是0
select a.c_id, a.c_name, sum(case when b.s_score<=100 and b.s_score>=85 then 1 else 0 end) as '[100-85]', sum(case when b.s_score<85 and b.s_score>=70 then 1 else 0 end) as '(85-70]', sum(case when b.s_score<70 and b.s_score>=60 then 1 else 0 end) as '(70-60]', sum(case when b.s_score<60 then 1 else 0 end) as '(<60)' from course as a left join score as b on a.c_id=b.c_id group by a.c_id;
2三、查询学平生均成绩及其名次
解题思路:
(1) 学生必定要包含全部学生,所以score中未包含全部学生,所以须要链接student表和score表
(2) 要查询每一个学生的平均成绩,就须要对s_id进行group by
(3) 使用rank()函数对平均分排序和打名次
select a.s_id, avg(b.s_score) as avg_score, rank() over(order by avg(b.s_score) desc) as 'rank' from student as a left join score as b on a.s_id=b.s_id group by a.s_id;
2四、查询各科成绩前三名的记录(不考虑成绩并列状况)
解题思路:
(1) 首先使用row_number()函数对score表中全部课程进行分组并对每门课程的全部学生分数进行排序
(2) 从上面的结果中筛选排序小于等于3的,则为各科成绩前三名
select * from ( select c_id, s_id, s_score, row_number() over(partition by c_id order by s_score desc) as 'row_number' from score ) as info where info.row_number<=3;
2五、查询每门课程被选修的学生数
解题思路:
(1) 在score表中对c_id进行group by
(2) 用count()函数统计每一个c_Id下的学生数
select c_id,count(s_id) from score group by c_id;
2六、查询出只有两门课程的所有学生的学号和姓名
解题思路:
(1) 须要使用到的字段有课程和姓名,所以链接student表和score表
(2) 要计算每一个学生的选课数,所以先对s_id进行group by
(3) 通过group by后,过滤条件为选课数量count(c_id)等于两门
select a.s_id,a.s_name from student as a left join score as b on a.s_id=b.s_id group by a.s_id having count(c_id)=2;
2七、查询男生、女生人数
解题思路:
(1) 直接在student表中对性别s_sex进行group by
(2) 随后使用count()函数便可统计男生人数和女生人数
select s_sex,count(s_id) from student group by s_sex;
2八、查询名字中含有"风"字的学生信息
解题思路:
(1) 在student表中操做便可
(2) 在筛选条件中使用模糊查询"%%"
select * from student where s_name like '%风%';
2九、查询1990年出生的学生名单
解题思路:
(1) 在student表中操做便可
(2) 筛选条件为出生日期s_birth的年份是1990,便可获得符合条件的学生
tips:这里会使用到year()函数,year(datetime)能够获得年份
select * from student where year(s_birth)=1990;
30、查询平均成绩大于等于85的全部学生的学号、姓名和平均成绩
解题思路:
(1) 须要的字段包含有姓名和成绩,所以链接student表和score表
(2) 计算平均成绩须要先对学号进行group by
(3) 过滤条件为平均成绩avg(s_score)大于等于85分,这样借的到符合条件的成绩
select a.s_id,a.s_name,avg(b.s_score) as avg from student as a left join score as b on a.s_id=b.s_id group by a.s_id having avg(b.s_score)>=85;
3一、查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列
解题思路:
(1) 在score表中操做便可
(2) 求每门课的平均成绩,须要先对课程编号进行group by
(3) 最后使用order by对平均成绩升序排序,平均成绩相同时按课程号降序排列
select c_id,avg(s_score) from score group by c_id order by avg(s_score),c_id desc;
3二、查询课程名称为"数学",且分数低于60的学生姓名和分数
解题思路:
(1) 须要使用到的字段有课程名称、姓名和分数,所以要链接student、score和course这三表
(2) 筛选条件为课程名称c_name为"数学",且分数s_score低于60
select a.s_name,b.s_score from student as a left join score as b on a.s_id=b.s_id left join course as c on b.c_id=c.c_id where c.c_name='数学' and b.s_score<60;
3三、查询全部学生的课程及分数状况
解题思路:
(1) 题目中说的是全部学生,所以须要使用student表左链接score表(由于可能存在没有选课的学生)
(2) 须要的是每一个学生的状况,所以先对学生编号进行group by
(3) 返回的字段格式为学生编号、语文成绩、数学成绩、英语成绩,所以要用到case when
select a.s_id, max(case when c.c_name='语文' then b.s_score else null end) as '语文',-- case when 当课程名字c_name是某门课时则获得这门课对应的成绩s_core max(case when c.c_name='数学' then b.s_score else null end) as '数学', max(case when c.c_name='英语' then b.s_score else null end) as '英语' -- 由于group by要与select列一致,因此case when须要加修饰max from student as a left join score as b on a.s_id=b.s_id left join course as c on b.c_id=c.c_id group by a.s_id;
3四、查询任何一门课程成绩在70分以上的姓名、课程名称和分数
解题思路:
(1) 首先从score表中选出每一个学生本身所选课程的成绩都在70分以上的学生编号
(2) 须要选出的字段有姓名、课程名称以及分数,所以链接student、score和course三张表
(3) 链接表的筛选条件为s_id含有第1步中的那些学生编号
select a.s_name, c.c_name, b.s_score from student as a left join score as b on a.s_id=b.s_id left join course as c on b.c_id=c.c_id where a.s_id in ( select s_id from score group by s_id having min(s_score)>=70 );
3五、查询学生不及格的课程并按课程号从大到小排列
解题思路:
(1) 在score表中操做便可
select c_id, s_id, s_score from score where s_score<60 order by c_id desc;