mysql 高频面试题(MySQL经典面试练习题)
mysql 高频面试题(MySQL经典面试练习题)数据:2.1:新建学生表student,包含sid 学生id,sname 学生姓名,sage 学生出生年月,ssex 学生性别4个字段。1:新建数据库 test。语句:createdatabasetest;2:按照如下字段数据库中新建对应表,并按照如下数据填充表格数据。
前言:
近期因为工作需要梳理了一些网上流传比较广的MySQL经典面试练习题,按照自己的理解从头写了一遍解法。有些特殊问题着重标记了思路和所涉及到的函数或语法点。共享给正在学习SQL或正在刷面试题的小伙伴们。
若对小伙伴们起到了帮助,欢迎点赞 收藏 转发~若具体到某个题目有更好的解题方法也欢迎大家留言或私信一起学习交流~
一 . 新建数据库及数据表
1:新建数据库 test。
语句:
createdatabasetest;
2:按照如下字段数据库中新建对应表,并按照如下数据填充表格数据。
2.1:新建学生表student,包含sid 学生id,sname 学生姓名,sage 学生出生年月,ssex 学生性别4个字段。
数据:
语句:
createtablestudent(sidvarchar(10) snamevarchar(10) sagedatetime ssexvarchar(10));
insertintostudentvalues('01' '赵雷' '1990-01-01' '男');
insertintoStudentvalues('02' '钱电' '1990-12-21' '男');
insertintoStudentvalues('03' '孙风' '1990-12-20' '男');
insertintoStudentvalues('04' '李云' '1990-12-06' '男');
insertintoStudentvalues('05' '周梅' '1991-12-01' '女');
insertintoStudentvalues('06' '吴兰' '1992-01-01' '女');
insertintoStudentvalues('07' '郑竹' '1989-01-01' '女');
insertintoStudentvalues('09' '张三' '2017-12-20' '女');
insertintoStudentvalues('10' '李四' '2017-12-25' '女');
insertintoStudentvalues('11' '李四' '2012-06-06' '女');
insertintoStudentvalues('12' '赵六' '2013-06-13' '女');
insertintoStudentvalues('13' '孙七' '2014-06-01' '女');
2.2:新建成绩表SC,包含sid 学生编号 cid 课程编号 score 分数 3个字段。
数据:
语句:
createtablesc(sidvarchar(10) cidvarchar(10) scoredecimal(3 1));
insertintoSCvalues('01' '01' 80);
insertintoSCvalues('01' '02' 90);
insertintoSCvalues('01' '03' 99);
insertintoSCvalues('02' '01' 70);
insertintoSCvalues('02' '02' 60);
insertintoSCvalues('02' '03' 80);
insertintoSCvalues('03' '01' 80);
insertintoSCvalues('03' '02' 80);
insertintoSCvalues('03' '03' 80);
insertintoSCvalues('04' '01' 50);
insertintoSCvalues('04' '02' 30);
insertintoSCvalues('04' '03' 20);
insertintoSCvalues('05' '01' 76);
insertintoSCvalues('05' '02' 87);
insertintoSCvalues('06' '01' 31);
insertintoSCvalues('06' '03' 34);
insertintoSCvalues('07' '02' 89);
insertintoSCvalues('07' '03' 98);
2.3:新建课程表course,包含cid 课程编号 cname 课程名称 tid教师编号3个字段。
数据:
语句:
createtablecourse(cidvarchar(10) cnamevarchar(10) tidvarchar(10));
insertintocoursevalues('01' '语文' '02');
insertintocoursevalues('02' '数学' '01');
insertintocoursevalues('03' '英语' '03');
2.4:新建教师表teacher,包含tid 教师编号 tname 教师姓名 2个字段。
数据:
语句:
createtableteacher(tidvarchar(10) tnamevarchar(10));
insertintoteachervalues('01' '张三');
insertintoteachervalues('02' '李四');
insertintoteachervalues('03' '王五');
2.5:观察4张表之间的联结关系,加深印象,便于后面题目中使用。
二. 题目
1.1. 查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数。
思路:
步骤1:分别查询课程01、02的学生及分数信息并视作临时表a、b;
步骤2:对2表联合查询学生及2课程分数信息,并限定条件“课程01成绩 > 课程02成绩”;
步骤3:将步骤2查询结果作临时表c,右联结至student表后查询所需信息,
函数:仅显示有数据的学生信息,故以student表为基础,右联结临时表c,需用到右联结函数right join
语句:
select*
fromstudentrightjoin
(selecta.sid score01 score02
from(selectsid scoreasscore01fromscwherecid='01')a
(selectsid scoreasscore02fromscwherecid='02')b
wherea.sid=b.sidandscore01>score02)c
onstudent.sid=c.sid;
结果:
1.2. 查询同时存在" 01 "课程和" 02 "课程的情况。
思路:分别查询学习了课程01、02的学生及课程分数信息,将2个查询结果分别视作2个临时表,并联表查询。
函数:inner join(),也可以用缩写join(),功能一样,都是取关联表的交集部分记录。
语句1:
select*
from(select*fromscwherecid='01')a
(select*fromscwherecid='02')b
wherea.sid=b.sid;
语句2:
select*
from(select*fromscwherecid='01')a
innerjoin
(select*fromscwherecid='02')b
ona.sid=b.sid;
结果:
1.3. 查询不存在" 01 "课程但存在" 02 "课程的情况。
思路:未选修了课程01但选修了课程02,在语法上无法直接写出。换个思路,选修了课程02但学生编号不在选修了课程01的学生编号集合中,一样的效果。
函数:不在某个集合中,涉及子集查询not in()
语句:
select*
fromsc
wherecid='02'andsidnotin(selectsidfromscwherecid='01');
结果:
2. 查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩。
思路:/
函数:avg()
语句1:直接查询
select s.sid s.sname avg(sc.score) as avg_score
from student s sc
where s.sid=sc.sid group by s.sid having avg(sc.score)>=60;
语句2:嵌套查询
select s.sid s.sname avg_score
from student s (select sid avg(sc.score) as avg_score
from sc
group by sid
having avg(sc.score)>=60)t
where s.sid=t.sid;
结果:
3. 查询在 SC 表存在成绩的学生信息。
思路:直接对student、sc联表查询,联结条件sid;或查询student并限定sid在sc表中有记录;再或者查询student并限定sid在sc表与student表中有交集。
函数:/
语句1:联合查询
selectdistincts.*fromstudents scwheres.sid=sc.sid;
语句2:嵌套查询,引入in函数
select*fromstudentwheresidin(selectsidfromsc);
语句3:嵌套查询,引入exists函数
select*fromstudentwhereexists(selectsidfromscwheresc.sid=student.sid);
结果:
4.1. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )。
思路:/
函数:计数函数count()、求和函数sum()
语句:
selects.* count(cid)as'选课总数' sum(score)as'课程总成绩'
fromstudentsleftjoinscons.sid=sc.sid
groupbysid;
结果:
提醒:题干要求“没成绩的显示NULL”,而此处若用where过滤相当于inner join取交集,则不会出现NULL情况。使用where的结果如下,可与上述结果对比差异。
错误语句:
selects.* count(cid)as'选课总数' sum(score)as'课程总成绩'
fromstudents sc
wheres.sid=sc.sidgroupbysid;
错误结果:
4.2. 查有成绩的学生信息。
思路:与题3一致
函数:/
语句1:联合查询
selectdistincts.*
fromstudentsinnerjoinscons.sid=sc.sid;
语句2:嵌套查询,引入in子集查询
select*
fromstudent
wheresidin(selectsidfromsc);
语句3:嵌套查询,引入exists函数
select*
fromstudent
whereexists(selectsidfromscwheresc.sid=student.sid);
结果:
5. 查询「李」姓老师的数量。
思路:/
函数:模糊查询,考察like以及通配符%的使用。
语句:
selectcount(tname)as'李姓老师数量'fromteacherwheretnamelike'李%';
结果:
6. 查询过「张三」老师授课的同学的信息。
思路:student s sc course teacher 四表联合查询
函数:/
语句:
selects.*
fromstudents sc coursec teachert
wheres.sid=sc.sidandsc.cid=c.cidandc.tid=t.tidandtname='张三';
结果:
7. 查询没有学全所有课程的同学的信息。
思路:反向思考,先把学全了全部课程(所选课程数等于实际所有课程数3)的同学信息先查询出来,再把这部分人从全部同学信息中过滤掉。
函数:not in()
语句:
select*
fromstudent
wheresidnotin
(selectsid
fromsc
groupbysid
havingcount(cid)=(selectcount(cid)fromcourse));
结果:
8. 查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息。
思路:反向查询,先查学号01学习的课程,再查询选修了这些课程的学号信息,再通过学号信息查询学生信息。
函数:/
语句:
select*
fromstudent
wheresidin
(selectsidfromscwherecidin
(selectcidfromscwheresid='01'));
结果:
9. 查询和" 01 "号的同学学习的课程完全相同的其他同学的信息。
思路:反向查询,先查询学号01学习的课程编号,在查询选修了这些课程的学号信息,加入过滤条件学号不等于01以及课程编号计数与01相等(或课程编号求和与01相等)。
函数:/
语句1:
select*
fromstudent
wheresidin
(selectsidfromscwherecidin(selectcidfromscwheresid='01')andsid!='01'
groupbysid
havingsum(cid)=(selectsum(cid)fromscwheresid='01'));
语句2:
select*
fromstudent
wheresidin
(selectsidfromscwherecidin(selectcidfromscwheresid='01')andsid!='01'
groupbysid
havingcount(cid)=(selectcount(cid)fromscwheresid='01'));
结果:
10. 查询没学过"张三"老师讲授的任一门课程的学生姓名。
思路:反向思维,先查询"张三"老师教过哪些课;再查出学过这些课的学生;反向查询不在这些学生中的其他学生,就是没学过"张三"老师课的学生。
函数:not in()
语句1:
select*
fromstudent
wheresidnotin
(selectsidfromscwherecidin
(selectcidfromcoursewheretidin
(selecttidfromteacherwheretname='张三')));
语句2:
select*
fromstudent
wheresidnotin
selects.sid
fromstudents sc course teacher
wheres.sid=sc.sid
andsc.cid=course.cid
andcourse.tid=teacher.tid
andteacher.tname='张三');
结果:
11. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩。
思路:/
函数:avg()、sum()
语句:
selects.sid s.sname avg(score)asavgscore
fromstudents sc
wheres.sid=sc.sidandscore<60
groupbys.sid
havingcount(score)>=2;
结果:
12. 检索" 01 "课程分数小于 60,按分数降序排列的学生信息。
思路:/
函数:/
语句:
selectstudent.* score
fromstudent sc
wherestudent.sid=sc.sidandcid='01'andscore<60
orderbyscoredesc;
结果:
13. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩。
思路1:从sc分别查询sid、3科的成绩、平均成绩分5列呈现到1个临时表,将student与此临时表进行关联查询出学生信息、成绩信息,关联条件sid,并按平均成绩降序排序;
函数:'sum()'、'case when'
语句:
selects.* score01 score02 score03 avg_score
fromstudents
(selectsid
sum(casewhencid='01'thenscoreelsenullend)asscore01
sum(casewhencid='02'thenscoreelsenullend)asscore02
sum(casewhencid='03'thenscoreelsenullend)asscore03
avg(score)asavg_score
fromsc
groupbysid)t
wheres.sid=t.sid
orderbyavg_scoredesc;
结果:
语句2:将student与学生的成绩表、平均成绩表(需单独创建临时表)联结后查询,语法内容较上述查询少,但呈现结果不如上述查询直观,不推荐。
函数:left join
语句:
select*
fromstudents
leftjoinscons.sid=sc.sid
leftjoin(selectsid avg(score)asavg_scorefromscgroupbysid)tons.sid=t.sid
orderbyt.avg_scoredesc;
结果:
14. 查询各科成绩最高分、最低分、平均分、及格率、中等率、优良率、优秀率,要求如下:
(1)及格:分数>=60,中等:80>分数≥70,优良:90>分数≥80,优秀:分数>=90;
(2)显示:课程编号、课程名、选修人数,查询结果按人数降序排列,若人数相同则按课程号升序排列。
思路:计算及格/中等/优良/优秀4个率时,先统计分子即符合各个区间的分数数量,再除以分母即总记录数,即为对应分数段比率。
函数:分数若符合某个区间要求则拟定返回1否则0,所有的返回值累加即为符合该区间的分数数量,此处引入'sum()'函数 'case when'函数。
语句:
selectsc.cidas'课程编号'
c.cnameas'课程名'
count(sc.cid)as'选修人数'
max(score)as'最高分'
min(score)as'最低分'
avg(score)as'平均分'
sum(casewhenscore>=60then1else0end)/count(*)as'及格率'
sum(casewhenscore>=70andscore<80then1else0end)/count(*)as'中等率'
sum(casewhenscore>=80andscore<90then1else0end)/count(*)as'优良率'
sum(casewhenscore>=90then1else0end)/count(*)as'优秀率'
fromsc coursec
wheresc.cid=c.cid
groupbysc.cid
orderbysc.cid;
结果:
15. 查询出只选修两门课程的学生学号和姓名。
思路:
函数:计数函数count()
语句:
selects.sid s.sname count(sc.cid)ascid_num
fromstudents sc
wheres.sid=sc.sid
groupbys.sid
havingcount(sc.cid)=2;
结果:
16.1 按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺。
思路:查询课程01、02、03、04成绩排名;将查询结果分别视作临时表t1\t2\t3 将student分别与之左联结后查询显示学生信息及各科排名信息,联结条件sid。
函数:涉及排序且题干要求重复时“保留名次空缺”,此处引入dense_rank() over (partition by 分区列 order by 排序列)。
语句:
selects.* rank_cid01 rank_cid02 rank_cid03
fromstudents
leftjoin(selectsid dense_rank()over(partitionbycidorderbyscore)asrank_cid01fromscwherecid='01')t1ons.sid=t1.sid
leftjoin(selectsid dense_rank()over(partitionbycidorderbyscore)asrank_cid02fromscwherecid='02')t2ons.sid=t2.sid
leftjoin(selectsid dense_rank()over(partitionbycidorderbyscore)asrank_cid03fromscwherecid='03')t3ons.sid=t3.sid
groupbys.sid
orderbys.sid;
结果:
16.2 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺。
思路:直接查询,查询科目总成绩,并对总成绩进行排序。
函数:涉及排序且题干要求重复时“不保留名次空缺”,此处引入rank() over (partition by 分区列 order by 排序列),可与15.1对比dense_rank区别。
selects.* sum(score)as'总成绩' rank()over(partitionbycidorderbyscore)as'总成绩排名'
fromstudents sc
wheres.sid=sc.sid
groupbys.sid;
结果:
16.3 按平均成绩进行排序,显示总排名和各科排名,Score 重复时保留名次空缺。
思路:与16.1一致,嵌套查询,分别查询各科目单独排名、科目总排名后合并显示。
函数:与16.1一致,涉及排序且题干要求重复时“保留名次空缺”,使用dense_rank() over (partition by 分区列 order by 排序列)。
语句:将上述查询分别视作临时表t1\t1\t3\t4 用student分别进行左联结后显示学生信息、各科排名及总排名,联结条件为sid,并以总排名排序。
selects.* rank_cid01 rank_cid02 rank_cid03 rank_all
fromstudents
leftjoin(selectsid dense_rank()over(partitionbycidorderbyscore)asrank_cid01fromscwherecid='01')t1ons.sid=t1.sid
leftjoin(selectsid dense_rank()over(partitionbycidorderbyscore)asrank_cid02fromscwherecid='02')t2ons.sid=t2.sid
leftjoin(selectsid dense_rank()over(partitionbycidorderbyscore)asrank_cid03fromscwherecid='03')t3ons.sid=t3.sid
leftjoin(selectsid dense_rank()over(orderbyavg(score)desc)asrank_allfromscgroupbysid)t4ons.sid=t4.sid
groupbys.sid
orderbyrank_all;
结果:
17. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比。
思路:统计出各个分数段人数,再使用各个分数段人数除以选课总人数即所占百分比;
函数:sum()、case when
语句:
selectsc.cidas'课程编号' c.cnameas'课程名称'
sum(casewhenscore>=85then1else0end)as'[100-85]人数'
sum(casewhenscore>=85then1else0end)/count(score)as'[100-85]占比'
sum(casewhenscore>=70andscore<85then1else0end)as'[85-70]人数'
sum(casewhenscore>=70andscore<85then1else0end)/count(score)as'[85-70]占比'
sum(casewhenscore>=60andscore<70then1else0end)as'[70-60]人数'
sum(casewhenscore>=60andscore<70then1else0end)/count(score)as'[70-60]占比'
sum(casewhenscore<60then1else0end)as'[60-0]人数'
sum(casewhenscore<60then1else0end)/count(score)as'[60-0]占比'
fromsc coursec
wheresc.cid=c.cid
groupbysc.cid;
结果:
18. 查询各科成绩前3名的记录。
思路:因为涉及对成绩排序,且排序前需根据课程编号限定排序分区,此处引入rank() over (partition by 分区列 order by 排序列)函数。
函数:rank() over()
语句:
select*
from(select* rank()over(partitionbycidorderbyscoredesc)asrank_scorefromsc)t
whererank_score<=3;
结果:
19. 查询每门课程被选修的学生数。
思路:/
函数:/
语句:
selectc.cid c.cname count(sc.cid)as'选修人数'
fromcoursec sc
wherec.cid=sc.cid
groupbyc.cid;
结果:
20. 查询出只选修两门课程的学生学号和姓名。
思路:/
函数:/
语句:
selects.sid s.sname count(cid)as'选修课程数'
fromstudents sc
wheres.sid=sc.sid
groupbys.sid
havingcount(cid)=2;
结果:
21. 查询男生、女生人数。
思路:/
函数:计数函数count()
语句:
selectssex count(ssex)as'人数'fromstudentgroupbyssex;
结果:
22. 查询名字中含有「风」字的学生信息。
思路:/
函数:模糊查询,考察like和通配符'%'的用法。
语句:
select*fromstudentwheresnamelike'%风%';
结果:
23. 查询同名同性学生名单,并统计同名人数。
思路:以学生姓名进行分组,并对姓名进行计数;筛选此查询结果中“姓名计数”>1(或≥2)的数据,即同名同姓的数据。
函数:计数函数count()
语句:
selectsname count(sname)as'姓名计数'
fromstudent
groupbysname
havingcount(sname)>1;
结果:
24. 查询 1990 年出生的学生名单。
思路:同第5题,考察模糊查询语句 like以及通配符%的使用。
函数:/
语句:
select*fromstudentwheresagelike'1990%';
结果:
25. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列。
思路:/
函数:avg()
语句:
selectsc.cid cname avg(score)asavg_score
fromsc coursec
wheresc.cid=c.cid
groupbysc.cid
orderbyavg(score)desc sc.cid;
结果:
26. 查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩。
思路1:嵌套查询。查询所有学生平均成绩;将结果视作临时表t,将student表与其联结后查询学生信息,并加入过滤条件平均分≥85;
函数:/
语句:
selects.* avg_score
fromstudents
(selectsid avg(score)asavg_scorefromscgroupbysid)t
wheres.sid=t.sidandt.avg_score>=85;
结果:
思路2:直接查询
函数:/
语句:
selects.* avg(score)asavg_score
fromstudents sc
wheres.sid=sc.sid
groupbys.sid
havingavg_score>=85;
结果:
27. 查询课程名称为 “数学”,且分数低于60的学生姓名和分数。
思路1:直接查询。直接对student、sc、course三遍联合查询,并加入科目为数学,分数小于60分条件过滤。
函数:/
语句:
selects.sname c.cname sc.score
fromstudents sc coursec
wheres.sid=sc.sidandsc.cid=c.cidandc.cname='数学'
groupbys.sname
havingsc.score<60;
结果:
思路2:嵌套查询。查询课程“数学”对应课程编号;反查选修了此编号的学生和分数信息;再与student进行联合查询,取学生姓名,分数信息,并加入过滤条件分数<60。
函数:/
语句:
selects.sname t.cid t.score
fromstudents
(selectsid cid scorefromscwherecidin(selectcidfromcoursewherecname='数学'))t
wheres.sid=t.sidandt.score<60;
结果:
28. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)。
思路:按题目要求即得知需以student表左联结sc表,即以student为主匹配选课和分数,而未选课无分数的学生对应信息则默认为空值。
函数:左联结函数left join()
selects.* sc.cid sc.score
fromstudentsleftjoinscons.sid=sc.sid;
结果:
提醒:有的同学会以student表右联结sc表,即以sc为主匹配student中有选课有分数的学生信息,这样的话未选课的学生信息不显示,则不符合题目要求“存在学生没成绩,没选课的情况”。
错误语句:
selects.* sc.cid sc.score
fromstudentsrightjoinscons.sid=sc.sid;
错误结果:
29. 查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数。
思路:任一课程>70,则平均成绩一定>70。先查询平均成绩>70的人;将查询结果与student、sc、course联合取姓名、课程信息、分数,并限定sid为平均成绩>70的人。
函数:in()、avg()
语句:
selects.sname c.cname sc.score
fromstudents sc coursec
wheres.sid=sc.sid
andsc.cid=c.cid
ands.sidin(selectsidfromscgroupbysidhavingavg(score)>70);
结果:
提醒:可能有些人会写成下属语句,看似正常实际结果错误,以下方“钱电”为例实际选修了3门课程:语文70,数学60,英语80,但只有英语>70其余均不符合,结果错误。
错误语句:
selects.sname c.cname sc.score
fromstudents sc coursec
wheres.sid=sc.sid
andsc.cid=c.cid
andsc.score>70;
错误结果:
30. 查询存在不及格的课程。
思路:查询分数小于60分的课程后对课程进行剔重;或查询分数小于60分的课程后对课程进行分组。
函数:/
语句1:
selectdistinctcidfromscwherescore<60;
语句2:
selectcidfromscwherescore<60groupbycid;
结果:
31. 查询课程编号为 01 且课程成绩在 80 分及以上的学生的学号和姓名。
思路:/
函数:/
语句:
selects.sid s.sname sc.cid sc.score
fromstudents sc
wheres.sid=sc.sid
andsc.cid='01'
andsc.score>=80;
结果:
32. 求每门课程的学生人数。
思路:/
函数:计数函数count()
语句:
selectcid count(sid)as'选课人数'fromscgroupbycid;
结果:
33. 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩。
思路:student、sc、course、teacher四表联合查询,用max函数求最高成绩后过滤;若不了解max函数,也可以将联合查询结果以分数降序排序后截取第1条数据,即最大值数据。
函数:最大值函数max()、limit极限函数(可用于截取限定记录)
语句:
语句1:
selects.* sc.score c.cid c.cname t.tname
fromstudents sc coursec teachert
wheres.sid=sc.sidandsc.cid=c.cidandc.tid=t.tidandt.tname='张三'
having(max(sc.score));
语句2:
selects.* sc.score c.cid c.cname t.tname
fromstudents sc coursec teachert
wheres.sid=sc.sidandsc.cid=c.cidandc.tid=t.tidandt.tname='张三'
orderbysc.scoredesc
limit1;
结果:
34. 成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩。
思路:通过查看原始表可得知没有成绩重复的情况,所以结果与33题一致,只有1条
函数:/
语句:
selects.* sc.score c.cid c.cname t.tname
fromstudents sc coursec teachert
wheres.sid=sc.sid
andsc.cid=c.cid
andc.tid=t.tid
andt.tname='张三'
andsc.scorein
(selectmax(sc.score)
fromstudents sc coursec teachert
wheres.sid=sc.sidandsc.cid=c.cidandc.tid=t.tidandt.tname='张三'andsc.score);
结果:
35. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩。
思路:
函数:inner join,也可直接用其缩写join,效果一样。
语句:
selecta.cid a.sid a.score
fromscasainnerjoinscona.sid=sc.sidanda.cid<>sc.cidanda.score=sc.score
groupbya.sid a.cid;
结果:
36. 查询每门功成绩最好的前两名。
思路:对每门功课排名,并取排名≤2的记录即可。
函数:排序函数rank() over()
语句:
select*
from(select* rank()over(partitionbycidorderbyscoredesc)asrank_scorefromsc)t
whererank_score<=2;
结果:
37. 统计每门课程的学生选修人数(超过 5 人的课程才统计)。
思路:/
函数:计数函数count()
语句:
selectcid count(sid)as'选修人数'
fromsc
groupbycid
havingcount(sid)>=5;
结果:
38. 检索至少选修两门课程的学生学号。
思路:/
函数:计数函数count()
语句:
selectsid count(cid)as'选修课程数'
fromsc
groupbysid
havingcount(cid)>=2;
结果:
39. 查询选修了全部课程的学生信息。
思路:/
函数:计数函数count()
语句:
selects.* count(cid)as'选修课程数'
fromstudents sc
wheres.sid=sc.sid
groupbysidhaving
count(cid)=(selectcount(cid)fromcourse);
结果:
40. 查询各学生的年龄,只按年份来算。
思路:/
函数:考察时间差函数,可以用timestampdiff,也可以用timestampdiff,思路都是计算当前时间与出生年月日的天数差,再换算为年数,区别见下方语句。
语句1:
select* timestampdiff(year sage curdate())asagefromstudent;
结果:
语句2:
select* datediff(curdate() sage)/365asagefromstudent;
结果:
注:上述2个语句本质上均可,区别在于查询1结果是整数,查询2结果带小数点更精确,但限于日常表述年龄一般都是整数,所以个人推荐查询1。
41. 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一。
思路:/
函数:case when()
语句:
select* casewhenmonth(curdate())<month(sage)andday(curdate())<day(sage)
thentimestampdiff(year sage curdate())-1
elsetimestampdiff(year sage curdate())
end)asage
fromstudent;
结果:
提醒:网上有的答案是按照如下语句写的,并未体现“当前月日 < 出生年月的月日则,年龄减一”的要求。
以‘钱电’为例,当前月日(笔者梳理时间2020/7/11)7月小于其出生月份12月,当前日11日小于其出生日21日,故原始年龄29-1后是28,下方结果不对。
错误语句:
select* timestampdiff(year sage curdate())asagefromstudent;
错误结果:
42. 查询本周过生日的学生。
思路:
函数:now()、week()
语句:
select*fromstudentwhereweek(sage)=week(now());
结果:Empty set (0.00 sec)
43. 查询下周过生日的学生。
思路:下周即为本周周数 1
函数:now()、week()
语句:
select*fromstudentwhereweek(sage)=(week(now()) 1);
结果:Empty set (0.00 sec)
44. 查询本月过生日的学生。
思路:
函数:now()、month()
语句:
select*fromstudentwheremonth(sage)=month(now());
结果:Empty set (0.00 sec)
45. 查询下月过生日的学生。
思路:下月即为本月月份 1
函数:now()、month()
语句:
select*fromstudentwheremonth(sage)=(month(now()) 1);
结果:Empty set (0.00 sec)
注:42~45涉及考察日期转换函数,如week-将日期转换为当年所在周数、month-将日期转换为所在月数。另关于当前时间获取:
(1)既可以用now(),既获取年月日还获取时分秒,对应格式'2020-08-08 12:00:00';
(2)也可以用curdate(),仅获取当前日期即年月日,对应格式'2020-08-08'。