MySQL-50道经典测试题-含自答案
- 数据表使用
- 1、4个学生表的构建结构
- 数据参考
- 题目快速导航
- 题1:查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数
- 题2:查询"01"课程比"02"课程成绩低的学生的信息及课程分数(-类比重复-题1了)
- 题3:查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
- 题4:查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩 -- (包括有成绩的和无成绩的)
- 题5:查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩
- 题6:查询"李"姓老师的数量
- 题7:查询学过"张三"老师授课的同学的信息
- 题8:查询没学过"张三"老师授课的同学的信息
- 题9:查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息
- 题10:查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息
- 题11:查询没有学全所有课程的同学的信息
- 题12:查询至少有一门课与学号为"01"的同学所学相同的同学的信息
- 题13:查询和"01"号的同学学习的课程完全相同的其他同学的信息
- 题14:查询没学过"张三"老师讲授的任一门课程的学生姓名
- 题15:查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
- 题16:检索"01"课程分数小于60,按分数降序排列的学生信息
- 题18:查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率,及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
- 题19:按各科成绩进行排序,并显示排名
- 题20:查询学生的总成绩并进行排名
- 题21:查询不同老师所教不同课程平均分从高到低显示
- 题22:查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
- 题23:统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比
- 题24:查询学生平均成绩及其名次
- 题25:查询各科成绩前三名的记录
- 题26:查询每门课程被选修的学生数
- 题27:查询出只有两门课程的全部学生的学号和姓名
- 题28:查询男生、女生人数
- 题29:查询名字中含有"风"字的学生信息
- 题30:查询同名同性学生名单,并统计同名人数
- 题31:查询1990年出生的学生名单
- 题32:查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
- 题33:查询平均成绩大于等于85的所有学生的学号、姓名和平均成绩
- 题34:查询课程名称为"数学",且分数低于60的学生姓名和分数
- 题35:查询所有学生的课程及分数情况
- 题36:查询任何一门课程成绩在70分以上的姓名、课程名称和分数
- 题37:查询课程不及格的学生
- 题38:查询课程编号为01且课程成绩在80分以上的学生的学号和姓名
- 题39:求每门课程的学生人数
- 题40:查询选修"张三"老师所授课程的学生中,成绩最高的学生信息及其成绩
- 题41:查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
- 题42:查询每门功成绩最好的前两名
- 题43:统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列, 若人数相同,按课程号升序排列
- 题44:检索至少选修两门课程的学生学号
- 题45:查询选修了全部课程的学生信息
- 题46:查询各学生的年龄
- 题47、查询本周过生日的学生
- 题48:查询下周过生日的学生
- 题49:查询本月过生日的学生
- 题50:查询下月过生日的学生
数据表使用
1、4个学生表的构建结构
- 学生表
| student | CREATE TABLE `student` (
`stuId` int(11) NOT NULL AUTO_INCREMENT COMMENT '学生号',
`stuName` varchar(20) NOT NULL COMMENT '学生名',
`stuSex` varchar(10) NOT NULL DEFAULT '待补' COMMENT '学生性别',
`stuDate` varchar(20) NOT NULL DEFAULT '待补' COMMENT '学生出生日',
PRIMARY KEY (`stuId`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| stuId | int(11) | NO | PRI | NULL | auto_increment |
| stuName | varchar(20) | NO | | NULL | |
| stuSex | varchar(10) | NO | | 待补 | |
| stuDate | varchar(20) | NO | | 待补 | |
+---------+-------------+------+-----+---------+----------------+
- 分数表
| stuScore | CREATE TABLE `stuScore` (
`stuId` int(11) DEFAULT NULL,
`couId` int(11) DEFAULT NULL,
`score` decimal(10,0) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| stuId | int(11) | YES | | NULL | |
| couId | int(11) | YES | | NULL | |
| score | decimal(10,0) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
- 老师表
| teacher | CREATE TABLE `teacher` (
`teaId` int(11) NOT NULL,
`teaName` varchar(20) NOT NULL DEFAULT '待补',
PRIMARY KEY (`teaId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| teaId | int(11) | NO | PRI | NULL | |
| teaName | varchar(20) | NO | | 待补 | |
+---------+-------------+------+-----+---------+-------+
- 科目表
| course | CREATE TABLE `course` (
`couId` int(11) NOT NULL AUTO_INCREMENT,
`couName` varchar(20) NOT NULL DEFAULT '待补',
`teaId` int(11) DEFAULT NULL,
PRIMARY KEY (`couId`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| couId | int(11) | NO | PRI | NULL | auto_increment |
| couName | varchar(20) | NO | | 待补 | |
| teaId | int(11) | YES | | NULL | |
+---------+-------------+------+-----+---------+----------------+
数据参考
insert into Student values(1 , '赵雷' , '1990-01-01' , '男');
insert into student values(2 , '钱电' , '1990-12-21' , '男');
insert into student values(3 , '孙风' , '1990-05-20' , '男');
insert into student values(4 , '李云' , '1990-08-06' , '男');
insert into student values(5 , '周梅' , '1991-12-01' , '女');
insert into student values(6 , '吴兰' , '1992-03-01' , '女');
insert into student values(7 , '郑竹' , '1989-07-01' , '女');
insert into student values(8 , '王菊' , '1990-01-20' , '女');
...
...
insert into course values(1 , '语文' , 2);
insert into course values(2 , '数学' , 1);
insert into course values(3 , '英语' , 3);
...
...
insert into teacher values(1 , '张三');
insert into teacher values(2 , '李四');
insert into teacher values(3 , '王五');
...
...
insert into stuScore values(1 , 1 , 80);
insert into stuScore values(1 , 2 , 90);
insert into stuScore values(1 , 3 , 99);
insert into stuScore values(2 , 1 , 70);
insert into stuScore values(2 , 2 , 60);
insert into stuScore values(2 , 3 , 80);
insert into stuScore values(3 , 1 , 80);
insert into stuScore values(3 , 2 , 80);
insert into stuScore values(3 , 3 , 80);
insert into stuScore values(4, 1 , 50);
insert into stuScore values(4 , 2 , 30);
insert into stuScore values(4 , 3 , 20);
insert into stuScore values(5 , 1 , 76);
insert into stuScore values(5 , 1 , 87);
insert into stuScore values(6 , 1 , 31);
insert into stuScore values(6 , 3 , 34);
insert into stuScore values(7 , 2 , 89);
insert into stuScore values(7 , 3 , 98);
题目快速导航
题1:查询" 01 “课程比” 02 "课程成绩高的学生的信息及课程分数
select student.*,t1.score as score01,t2.score as score02
from student,
(select stuId,score from stuScore where stuScore.couId=1) as t1,
(select stuId,score from stuScore where stuScore.couId=2) as t2
where t1.stuId = t2.stuId and t1.score>t2.score
and student.stuId=t1.stuId;
题2:查询"01"课程比"02"课程成绩低的学生的信息及课程分数(-类比重复-题1了)
select student.*,t1.score as score01,t2.score as score02
from student,
(select stuId,score from stuScore where stuScore.couId=1) as t1,
(select stuId,score from stuScore where stuScore.couId=2) as t2
where t1.stuId = t2.stuId and t1.score<t2.score
and student.stuId=t1.stuId;
题3:查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
select student.stuId,student.stuName,round(avg(stuScore.score),2) as Averge from
student inner join stuScore
on student.stuId=stuScore.stuId
group by student.stuId
having AVG(stuScore.score)>=60;
题4:查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩 – (包括有成绩的和无成绩的)
select student.stuId,student.stuName,
(case when AVG(sc1.score) is null then 0 else AVG(sc1.score)end) from
student
left join stuScore as sc1
on student.stuId=sc1.stuId
group by student.stuId
having AVG(sc1.score)<60 or AVGG(sc1.score) is null;
题5:查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩
#土方法,排序上有点小问题
select student.stuId,student.stuName,t1.score as score01,t2.score as score02,t3.score as score03,
((case when t1.score is null then 0 else t1.score end)+(case when t2.score is null then 0 else t2.score end)+(case when t3.score is null then 0 else t3.score end)) as sumScore,
((case when t1.score is null then 0 else1 end)+(case when t2.score is null then 0 else 1 end)+(case when t3.score is null then 0 else 1 end)) as count
from student
left join (select * from stuScore where couId=1) as t1
on student.stuId=t1.stuId
left join (select * from stuScore where couId=2) as t2
on t1.stuId = t2.stuId
left join (select * from stuScore where couId=3) as t3
on t1.stuId=t3.stuId;
#新方法,排序上无问题
select student.stuId,student.stuName,COUNT(stuScore.couId) as count,SUM(stuScore.score) as sumScore
from student
left join stuScore
on student.stuId=stuScore.stuId
group by student.stuId;
#优化一下,可以避免SUM结果出现null的情况,使用分支语法就可
select student.stuId,student.stuName,COUNT(stuScore.couId) as count,(case when SUM(stuScore.score) is null then 0 else SUM(stuScore.score) end) as sumScore
from student
left join stuScore
on student.stuId=stuScore.stuId
group by student.stuId;
题6:查询"李"姓老师的数量
select count(*) as count from teacher where teaName like '李%';
题7:查询学过"张三"老师授课的同学的信息
select student.*,course.couId,teacher.teaName
from teacher
left join course on teacher.teaId=course.teaIdteaId
left join stuScore on stuScore.couId=course.couId
left join student on student.stuId=stuScore.stuId
where teacher.teaName='张三';
题8:查询没学过"张三"老师授课的同学的信息
select student.* from student
where student.stuId
not in (select stuScore.stuId from stuScore
where stuScore.couId
in (select course.couId from course left join teacher on course.teaId=teacher.teaId where teacher.teaName='张老师'));
题9:查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息
#法一:偏算术算法
select student.* from student
where stuId
in (select stuId from stuScore
where couId in (1,2)
group by stuId
having count(*)!=1);
#法二:偏表表联系
select student.* from student
where stuId
in(select t1.stuId from (select * from stuScore where couId=1) as t1
inner join (select * from stuScore where couId=2) as t2
on t1.stuId=t2.stuId );
题10:查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息
#法一:偏分表联系
select student.* from student
where stuId
in (select stuId from stuScore where couId=1)
and stuId
not in (select stuId from stuScore where couId=2);
#法二:group by 分组往下探头
#(每个学生都不存在只有一个成绩,在经典50题的表适用)
select student.*
from student
left join stuScore
on student.stuId=stuScore.stuId
group by student.stuId
having count(*)<=2 and sum(couId)=4;#(1+3=4)
#(当存在只有一个成绩的时候,就会冲昏‘3’=‘1+2’)
#这里给couId加1,加强和运算后的独立
#当一位数时:1-2-3--+1-->2-3-4
#当二位数时:1+2-2+3-1+3--+1-->2+3-3+4-2+4-->5-7-6
#此时一位和二位成绩存在已经无关,不能冲昏,【完成】
select student.*
from student
left join stuScore
on student.stuId=stuScore.stuId
group by student.stuId
having count(*)<=2 and sum(stuScore.couId+1) in (2,4,6);
题11:查询没有学全所有课程的同学的信息
#比较优的方法
select student.*
from student
left join stuScore
on student.stuId=stuScore.stuId
group by student.stuId having count(couId)<(select count(*) from course);
# having count(couId)<(select count(*) from course);
# having SUM(couId)<(select SUM(couId) from course);
#为什么不能直接count(course.couId),因为course表没在最外层的from范围内
#杂但是理解简单的方法:表表联系
select student.*,t1.score as score01,t2.score as score02,t3.score as score03
from student
left join (select * from stuScore where couId=1) as t1
on student.stuId = t1.stuId
left join (select * from stuScore where couId=2) as t2
on student.stuId = t2.stuId
left join (select * from stuScore where couId=3) as t3
on student.stuId = t3.stuId
where t1.score is null
or t2.score is null
or t3.score is null;
题12:查询至少有一门课与学号为"01"的同学所学相同的同学的信息
#第一个直觉是,集合问题
#因为要先知道01同学的选课大集合,才能从总的若个集合中有交集就显示
select student.*
from student
left join stuScore as t1
on t1.stuId=student.stuId
where t1.couId
in(select t2.couId from stuScoret2 where t2.stuId=1);
题13:查询和"01"号的同学学习的课程完全相同的其他同学的信息
#比较优的方法:用了一下couId+1的数字和运算区分
#也是有点集合问题的直觉
select student.*
from student
left join stuScore as t1
on student.stuId = t1.stuId
group by student.stuId
having sum(t1.couId+1)=
(select sum(t2.couId+1) from stuScore as t2 group by t2.stuId having t2.stuId=1);
题14:查询没学过"张三"老师讲授的任一门课程的学生姓名
#无赖打法:一层一层拨开你的心,有点串联信息交流的意思,
#需要的信息总是由一个又一个的系统的输出作为输入
select student.* from student
where stuId not in
(select stuScore.stuId from stuScore
where stuScore.couId=
(select course.couId from course
where teaId=
(select teaId from teacher
where teaName='张老师')));
#表表联系:最后来个刺激
select * from student
where stuId
not in
(select stuId from stuScore
inner join course on stuScore.couId=course.couId
inner join teachereacher on teacher.teaId=course.teaId
where teaName='张老师');
题15:查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
#无赖打法:乱打一通
select student.stuId,student.stuName,t1.avgScore
from student #学生信息来源
inner join #平均成绩来源(平均成绩包含及格的成绩一起算)
(select stuScore.stuId,avg(score) as avgScore
from stuScore
#必须重新回到成绩表获得平均成绩,而不是从拿到的不及格表拿到平均成绩
group by stuScore.stuId) as t1 on student.stuId=t1.stuId
where student.stuId
in(select temp1.stuId from
(select * from stuScore as t1 where score < 60 ) as temp1
group by temp1.stuId having count(*)>=2);#拿到超2科的不及格成绩表
#集合联系:
#注意:如果再同一范围的语句中就算平均值就会被where语句给抢掉
#比如:三个数,50,40,80
#被where抢前后,计算的平均值只能是(50+40)/2
#而不是正确意义上的(50+40+80)/3
select student.stuId,student.stuName,AVG(t1.score)
from student
left join stuScore as t1 on student.stuId=t1.stuId
where t1.stuId
in
(select t2.stuId from stuScore t2
where t2.score<60 or t2.score is null
group by t2.stuId
having count(t2.stuId)>=2)
group by student.stuId;
题16:检索"01"课程分数小于60,按分数降序排列的学生信息
#垃圾题目
select * from student
left join (select * from stuScore where couId=1) as t1
on student.stuId=t1.stuId
where score<60 order by score desc;
#表表联系:汇总最后一击
select student.stuName,t1.score as score01,t2.score as score02,t3.score as score03,t4.AvgScore
from student
left join (select * from stuScore where couId=1) as t1 on student.stuId=t1.stuId
left join (select * from stuScore where couId=2) as t2 on student.stuId=t2.stuId
left join (select * from stuScore where couId=3) as t3 on student.stuId=t3.stuId
left join (select temp1.stuId,avg(temp1.score) as AvgScore from stuScore as temp1 group by temp1.stuId) as t4 on t4.stuId=student.stuId
order by t4.AvgScore desc;
#↑有个误区是在第四表连接中,容易用
#left join stuScore on xx.stuId=xx.stuId group by student.stuId ...
#是出现了类似的可以进行分组查询的新式表,但是实际上这张表是3个及以上所形成的的,
#而你t4只跟student用on关联起来了,当你使用student的stuId的时候,就会视t1表不见
#所以就会出现t1.score无法参与group by
题18:查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率,及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
#方法笨了点,“我丑但是我很温柔”,但是易懂:采用全count计数器计算率的问题
#数据来源一张一张的表
select
t1.couId '课程ID',t1.couName '课程名称',
t1.max '最高分',t1.min '最低分',t1.avg '平均分',
t2.cnt2/t1.cnt1 '及格率',t3.cnt3/t1.cnt1 '中等率'
,t4.cnt4/t1.cnt1 '优良率',t5.cnt5/t1.cnt1 '优秀率'
from
(select course.couId, course.couName,max(score) as max,min(score)as min,avg(score)as avg,count(*) as cnt1
from stuScore
left join course on stuScore.couId=course.couId group by course.couId) as t1 left join (select stuScore.couId,count(*) as cnt2 from stuScore where score>=60
group by stuScore.couId
)
as t2 on t1.couId=t2.couId
left join
(select stuScore.couId,count(*) as cnt3
from stuScore
where score>=70 and score<80
group by stuScore.couId
)
as t3 on t1.couId=t3.couId
left join
(select stuScore.couId,count(*) as cnt4
from stuScore
where score>=80 and score<90
group by stuScore.couId
)
as t4 on t1.couId=t4.couId
left join
(select stuScore.couId,count(*) as cnt5
from stuScore
where score>=90 and score<=100
group by stuScore.couId
)
as t5 on t1.couId=t5.couId
order by t1.couId;
#眨眼一看,一坨shit
#新方法:偏算法判断类型,用条件判断做计时器,即01计时器
select course.couId '课程ID',course.couName '课程名称',max(score)'最高分',min(score)'最低分',avg(score)'平均分',
(sum(case when score>=60 then 1 else 0 end)/count(*)) as '及格率' ,
(sum(case when score>=70 and score<80 then 1 else 0 end)/count(*)) as '中等率',
(sum(case when score>=80 and score<90 then 1 else 0 end)/count(*)) as '优良率' ,
(sum(case when score>=90 and score<=100 then 1 else 0 end)/count(*)) as '优秀率'
from stuScore left join course on stuScore.couId=course.couId group by course.couId;
题19:按各科成绩进行排序,并显示排名
#不显示排名就这样,简简单单,难就难在要显示排名
select t1.*,course.couName,student.stuName from stuScore as t1 left join student on t1.stuId=student.stuId left join course on course.couId=t1.couId order by t1.couId,t1.score desc;
#那就要插入一个列,这个列在所存在的表也是没有。
#只能引入一个变量了
#而且这个变量要在couId一变就重新排列
#用变量的时候,注意一下MySQL的非存储过程的执行过程也是有顺序的
#这里要知道select到from这其中是挑选字段的范围
#要在表构建完后才进行挑选,所以这里的语句是比from中表源后一些的
#这也能解释为什么要先在from后跟一个变量定义或变量赋值
#然而cross join 是为什么?
#因为这个表连接,好像是没什么关系的连,它连on字段的联系都没有。
select (@i:=case when @couIdFlow = t2.couId then @i+1 else 1 end) as 'NO.' ,(@couIdFlow:=t2.couId) as couId,
t2.couName,t2.score,t2.stuName
from (select @i := 0, @couIdFlow := 1) as forDefineValue
cross join
(select t1.*,course.couName,student.stuName from stuScore as t1
left join student on t1.stuId=student.stuId
left join course on course.couId=t1.couId
order by t1.couId,t1.score desc
) as t2;
题20:查询学生的总成绩并进行排名
#如果这里,关于19题的变量有一定的见解后,也是比较简单了。
#我们先不显示排名的进行sum排序一下,然后再加入显示排名的一列
#比如这里,我们要借助i变量来显示,并依次每一条记录来+1往下显示就可以
#然后需要定义变量或叫初始化变量的值
#使用cross join这种无关痛痒的手法
select (@i:=@i+1) as 'NO.',t2.*
from (select @i := 0) as forDefineValue
cross join
(select student.stuId,student.stuName,sum(t1.score) as sumScore
from stuScore as t1
left join student on student.stuId=t1.stuId
group by t1.stuId
order by sum(t1.score) desc
)
as t2;
题21:查询不同老师所教不同课程平均分从高到低显示
#这是一个比较直观的方法了,主要通过group by来划分
#--因为版本问题,如果使用group by 后面只接一个字段的话,会报错
#--主要还是因为full_group_by这个模式的原因
#--好像是某个版本5.7.x之后,就默认开启了这个模式,叫什么依赖关系的
#--这里,teacher表和course表都能一一对应
#--所以用两个字段来分组好像也没什么关系了。
#--据了解,好像是select所选中的字段中,除了聚合函数外,
#--都要在group by中参与
#--而实际中,却只是用了来自不同表的teaId和couId
#--当更换course的couId为couName时候,又报错
#--所以啊,初步认为跟“依赖关系”有关,我们在构建表表关系的时候
#--用了teaId和couId
#--而且我怀疑跟表设置主键或表之间构建关联的字段有点关系
select tea.teaId,tea.teaName,cou.couId,cou.couName,avg(t1.score) as avgScore
from teacher as tea
left join course as cou on tea.teaId=cou.teaId
left join stuScore as t1 on t1.couId=cou.couId
group by tea.teaId,cou.couId
order by avg(t1.score) desc;
#方法二:
#上面的方法是直接用三表联立,且group by建立在三表联立下
#这就必须要group by 时候,选中select中的不同表的被联系字段
#下面这种方法是把group by 框在某个内层表内
select tea.teaId,tea.teaName,couAndAvg.*
from teacher as tea
left join
(select course.*,avg(score) as avgScore
from course
left join stuScore on course.couId=stuScore.couId
group by couId
)
as couAndAvg on tea.teaId=couAndAvg.teaId
order by avgScore desc;
题22:查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
#土方法:我感觉有点无赖,使用了变量来排名,然后再联系学生ID
select student.*,rankTable.number as 'NO.',rankTable.couId,rankTable.score
from student
left join
(select
(@i:=case when @couIdFlow=t1.couId then @i+1 else 1 end)as number,
(@couIdFlow:=t1.couId) as couId,
t1.stuId,t1.score
from (select @i:=0,@couIdFlow:=1) as var
cross join stuScore as t1
order by t1.couId asc,t1.score desc
)
as rankTable on student.stuId=rankTable.stuId
where rankTable.number between 2 and 3;
#另一种没什么mysql的思想的
#把各自的表拿出外面,再用union all 来往下拼接
(select student.*,t1.couId,t1.score from stuScore as t1 left join student on student.stuId=t1.stuId where t1.couId=1 order by score desc limit 1,2)
union all
(select student.*,t2.couId,t2.score from stuScore as t2 left join student on student.stuId=t2.stuId where t2.couId=2 order by score desc limit 1,2)
union all
(select student.*,t3.couId,t3.score from stuScore as t3 left join student on student.stuId=t3.stuId where t3.couId=3 order by score desc limit 1,2);
题23:统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比
#方法就是使用二表联立
#这里的group by为什么没有使用select后面的另一张表course.couName?
#我只能说再二表联立的时候使用了couId字段
#且couName也不是主键,这就不知道从哪区分开来
select t1.couId ,course.couName,count(*) as cntAll,
sum(case when t1.score between 85 and 100 then 1 else 0 end)/count(*) as '[100-85]',
sum(case when t1.score between 70 and 85 then 1 else 0 end)/count(*) as '[85-70]',
sum(case when t1.score between 60 and 70 then 1 else 0 end)/count(*) as '[70-60]',
sum(case when t1.score between 0 and 60 then 1 else 0 end)/count(*) as '[0-60]'
from stuScore as t1
left join course on t1.couId =course.couId
group by t1.couId;
#第二种方法:还不如说是第二种表示,因为其实是一样的
select a0.couId,cou.couName,a0.cnt0 as 'cntAll',
a1.cnt1/a0.cnt0 as '[100-85]',
a2.cnt2/a0.cnt0 as '[85-70]',
a3.cnt3/a0.cnt0 as '[70-60]',
a4.cnt4/a0.cnt0 as '[60-70]'
from course as cou
left join
(select couId,count(*) as cnt0
from stuScore
group by couId
)
as a0 on cou.couId=a0.couId
left join
(select couId,count(*) as cnt1
from stuScore
where score between 85 and 100
group by couId
)
as a1 on a0.couId=a1.couId
left join
(select couId,count(*) as cnt2
from stuScore
where score between 70 and 85
group by couId
)
as a2 on a0.couId=a2.couId
left join
(select couId,count(*) as cnt3
from stuScore
where score between 60 and 70
group by couId
)
as a3 on a0.couId=a3.couId
left join
(select couId,count(*) as cnt4
from stuScore
where score between 0 and 60
group by couId
)
as a4 on a0.couId=a4.couId;
#先到这里吧!一坨shit
题24:查询学生平均成绩及其名次
#其实这张表有点不清晰,
#究竟没录入stuScore表的成绩是学生缺考=0分
#还是说学生不用学这门课
#以下是对”不用学“的表示,总分除以参加考试的科目
select (@i:=@i+1) as 'NO.',
resultTable.stuId,resultTable.stuName,resultTable.avgScore
from (select (@i:=0))as var
cross join
(select student.stuId,student.stuName,avg(t1.score) as avgScore
from student
left join stuScore as t1 on student.stuId=t1.stuId
group by stuId
order by avg(t1.score) desc
) as resultTable;
#以下是一种缺考为0分共计入计算的
select (@i:=@i+1) as 'NO.',
resultTable.stuId,resultTable.stuName,resultTable.avgScore
from (select (@i:=0))as var
cross join
(select student.stuId,student.stuName,
sum(t1.score)/(select count(*) from course) as avgScore
from student
left join stuScore as t1 on student.stuId=t1.stuId
group by stuId
order by sum(t1.score)/3 desc
) as resultTable;
题25:查询各科成绩前三名的记录
#赖皮蛇玩法:union all 串一串
(select stu.*,t1.score,t1.couId,course.couName from student as stu left join stuScore as t1 on stu.stuId=t1.stuId left join course on course.couId=t1.couId where t1.couId=1 order by t1.score desc limit 0,3)
union all
(select stu.*,t1.score,t1.couId,course.couName from student as stu left join stuScore as t1 on stu.stuId=t1.stuId left join course on course.couId=t1.couId where t1.couId=2 order by t1.score desc limit 0,3)
union all
(select stu.*,t1.score,t1.couId,course.couName from student as stu left join stuScore as t1 on stu.stuId=t1.stuId left join course on course.couId=t1.couId where t1.couId=3 order by t1.score desc limit 0,3)
#第二种方法,从变量排名中筛出来
#之前那道题用过了
select student.*,hasRank.number,hasRank.couName,hasRank.score
from
(select
(@i:=case when @couIdFlow=result.couId then @i+1 else 1 end) as number,
(@couIdFlow:=result.couId) as flow2,result.*
from
(select @i:=0,@couIdFlow:=1) as var
cross join
(select t1.stuId,course.couName,t1.score,t1.couId
from stuScore as t1
left join course on t1.couId=course.couId
order by t1.couId asc,t1.score desc
) as result
) as hasRank
left join
student on student.stuId=hasRank.stuId
where hasRank.number between 1 and 3;
题26:查询每门课程被选修的学生数
#实际上这个问题就很奇异了,因为我想了一下,这不是很简单吗?
#因为没选某门课的学生再stuScore里面就是没有显示啊
select cou.couId,cou.couName,count(t1.couId) as studentNumber
from stuScore as t1
left join course as cou
on cou.couId=t1.couId
group by t1.couId;
题27:查询出只有两门课程的全部学生的学号和姓名
#突然这么简单,有点不适应
select student.stuId,student.stuName
from student
left join stuScore as t1 on t1.stuId=student.stuId
group by stuId
having count(*)=2;
题28:查询男生、女生人数
select student.stuSex,count(*) as sexNumber
from student
group by stuSex;
题29:查询名字中含有"风"字的学生信息
#太假啦!太假了!
select * from student where stuName like '%浩%';
题30:查询同名同性学生名单,并统计同名人数
#用一张表,用分组计数,查询就好
#使用group by就要考虑版本默认与否开启group by mole的问题
#如果是没开启的,或者关闭掉的,这里使用studen.*就可以了
select student.stuName,student.stuSex,count(*)
from student
group by student.stuName,student.stuSex
having count(*)>1;
#另一种比较人性化的方法:如下
select student.stuName,student.stuSex,count(*) as 'all'
,group_concat(stuId) as 'stuId'
from student
group by student.stuName,student.stuSex
having count(*)>1;
#如果要查询学生信息的话是如下
#为什么不用left join 或其他的join
#这样会把t1和t2一条一条连接起来,查询的时候也是一条一条
#这样也就是说,当你用stuId关联起来
#在查到某条stuId=2的时候,另一张表并不能用别的stuId滑动
#只能是stuId=2
#使用cross join 就是因为它的”毫无关系“
#只是因为要用到第二张表来做条件判断
select t1.* from student as t1
cross join student as t2
where t1.stuId!=t2.stuId
and t1.stuName=t2.stuName
and t1.stuSex=t2.stuSex
order by t1.stuId;
题31:查询1990年出生的学生名单
#如果你在stuDate,学生生日字段使用了varchar类型,那么以下就行
select * from student where stuDate like '1990%';
#如果使用的是Date类型,那么就要
select * from student where year(stuDate) = '1990';
题32:查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
select t1.couId,avg(t1.score)
from stuScore as t1
group by t1.couId
order by avg(t1.score) desc,couId asc;
题33:查询平均成绩大于等于85的所有学生的学号、姓名和平均成绩
select student.stuId,student.stuName,avg(t1.score)
from student
left join stuScore as t1 on student.stuId=t1.stuId
GROUP BY student.stuId
having avg(t1.score)>=85;
题34:查询课程名称为"数学",且分数低于60的学生姓名和分数
#方法:总表再筛选
select student.*,t2.couName,t1.score
from student
left join stuScore as t1 on t1.stuId=student.stuId
left join course as t2 on t2.couId=t1.couId
where t2.couName='数学'
and t1.score<60;
#这一种也差不多吧。只是说可能速度会快一点点点点
select student.*,t2.couName,t1.score
from student
left join stuScore as t1 on t1.stuId=student.stuId and t1.score<60
left join course as t2 on t2.couId=t1.couId
where t2.couName='数学';
题35:查询所有学生的课程及分数情况
#如果是为了符合要求的话,不要求美化的话,以下通过普普通通的表表联立
select student.*,t2.couName,t1.score
from student
left join stuScore as t1 on t1.stuId=student.stuId
left join course as t2 on t2.couId=t1.couId;
#如果要为了美化的话,即一条记录里面有各课程字段和各分数
select student.*
,r1.score as 'score01'
,r2.score as 'score02'
,r3.score as 'score03'
from student
left join
(select stuId,score from stuScore where couId=1
) as r1 on r1.stuId=student.stuId
left join
(select stuId,score from stuScore where couId=2
) as r2 on r2.stuId=student.stuId
left join
(select stuId,score from stuScore where couId=3
) as r3 on r3.stuId=student.stuId;
题36:查询任何一门课程成绩在70分以上的姓名、课程名称和分数
#如果是为了符合要求的话,不要求美化的话,以下通过普普通通的表表联立
select student.stuName,cou.couName,t1.score from student left join (select * from stuScore where score>=70 ) as t1 on student.stuId=t1.stuId left join course as cou on cou.couId=t1.couId;
#如果要为了美化的话,即一条记录里面有各课程字段和各分数
select student.stuName
,group_concat(couName,score separator ' ; ') as 'course and score'
from student
inner join
(select * from stuScore where score>=70 ) as t1
on student.stuId=t1.stuId inner join course as cou
on cou.couId=t1.couId
group by student.stuName;
题37:查询课程不及格的学生
#可以沿用上面的‘美化’方法
select student.stuName
,group_concat(couName,score separator ' ; ') as 'course and score'
from student
inner join
(select * from stuScore where score<60 ) as t1
on student.stuId=t1.stuId inner join course as cou
on cou.couId=t1.couId
group by student.stuName;
#也可以使用不美化的方法,就不列举了,改个判断条件就行了。
#当当符合题目要求就行的,
#使用inner join 是为了某些没选这门课的学生不出现
select student.*
from student
inner join
(select distinct stuId from stuScore where score<60
)as r1 on r1.stuId=student.stuId;
题38:查询课程编号为01且课程成绩在80分以上的学生的学号和姓名
#又突然出现这么简单的题,有点不太适应
select student.stuId,student.stuName
from student
inner join stuScore as t1 on t1.stuId=student.stuId
where couId=1 and score>=80;
题39:求每门课程的学生人数
- 这道题不就是二十六题吗?【26:查询每门课程被选修的学生数】
#还是写一下吧,但是写一个就好了,不加课程名称:
select couId,count(*) from stuScore group by couId;
#加课程名称:
select course.couId,course.couName,count(*) from stuScore as t1 left join course on course.couId=t1.couId group by course.couId;
题40:查询选修"张三"老师所授课程的学生中,成绩最高的学生信息及其成绩
#这一道题一看就要三表联立了,张三老师要用teacher表,
#张三老师所授课程要用course表
#找到成绩和对比要用stuScore表
#要拿到学生信息要用student表
#方法1:赖皮蛇打法,玩一套多重嵌套,或子父关系输出的,
#即某张表需要的某个输入从另一张表得到
select student.*,sco.couName,sco.score from student
inner join
(select stuId,couName,score from stuScore
inner join
(select couId,couName from course
inner join
(select teaId from teacher
where teaName='张老师'
)
as tea
on tea.teaId=course.teaId
)
as cou on cou.couId=stuScore.couId
order by stuScore.score desc limit 0,1
)
as sco on sco.stuId=student.stuId;
#方法二:,表表联立,总表出来再筛选,简简单单的思想,不玩脑回路
select student.*,tea.teaName,cou.couName,t1.score
from student
left join stuScore as t1 on t1.stuId=student.stuId
left join course as cou on cou.couId=t1.couId
left join teacher as tea on tea.teaId=cou.teaId
where tea.teaName='张老师'
order by score desc
limit 0,1;
题41:查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
#这是一种没有美化的方式,能够符合要求,但是不够美化
#这里还是group by里面体现了,按每条记录筛选的可能
#当 stuId couId1 couId2 socre
# 2 1 2 58
# 2 1 3 58
#会合并为一条 2 1(couid1)58
#看起来couId1 和 couId2 中[1,2]和[1,3]并不属于一组
#但是经过cross join 后和筛选后,有多出来一般
#而这样的group by 又能够缩少一半,这样就比较无厘头的完成了效果
select t1.stuId,t1.couId,t1.score
from stuScore as t1
cross join stuScore as t2
where t1.stuId=t2.stuId
and t1.couId!=t2.couId
and t1.score=t2.score
group by t1.stuId,t1.couId,t1.score;
#方法2:偏算法类型,一种依靠聚合函数的
#
select stuScore.* from stuScore
inner join
(select t1.stuId,t1.score
from stuScore as t1
group by t1.stuId,t1.score having count(*)>=2
) as r1
on stuScore.stuId=r1.stuId and stuScore.score=r1.score;
#方法3:
#这里是稍微美化的一种,因为配置文件的问题,
#在select字段再命名的时候,因为不能再where后面起作用
#所以使用了一个一级嵌套来用
#方法的思路是“01挥旗方法flag”
select distinct result.*
from
(select r1.stuId
,(case when a1.score=a2.score or a1.score=a3.score then 1 else 0 end )as course01
,(case when a1.score=a2.score or a3.score=a2.score then 1 else 0 end )as course02
,(case when a1.score=a3.score or a3.score=a2.score then 1 else 0 end )as course03
,r1.score
from
stuScore as r1
left join(select stuId,score from stuScore where couId=1)as a1 on r1.stuId=a1.stuId
left join(select stuId,score from stuScore where couId=2)as a2 on r1.stuId=a2.stuId
left join(select stuId,score from stuScore where couId=3)as a3 on r1.stuId=a3.stuId
) as result
where result.course01=1 or result.course02=1 or result.course03=1 ;
#方法4:采用group_concat
select r2.stuId,r2.score
,group_concat(r2.couId order by r2.couId asc) as 'couId'
from
(select stuScore.* from stuScore
inner join
(select t1.stuId,t1.score
from stuScore as t1
group by t1.stuId,t1.score having count(*)>=2
) as r1
on stuScore.stuId=r1.stuId and stuScore.score=r1.score
) as r2
group by r2.stuId,r2.score;
题42:查询每门功成绩最好的前两名
#方法一:用union all 无赖打法,如果不要求显示学生名字
(select * from stuScore where couId=1 order by score desc limit 0,2)
union all
(select * from stuScore where couId=2 order by score desc limit 0,2)
union all
(select * from stuScore where couId=3 order by score desc limit 0,2);
#要用学生名字?也简单
select student.stuId,student.stuName,r1.couId,r1.score from student inner join((select * from stuScore where couId=1 order by score desc limit 0,2)
union all
(select * from stuScore where couId=2 order by score desc limit 0,2)
union all
(select * from stuScore where couId=3 order by score desc limit 0,2))as r1 on student.stuId=r1.stuId;
#方法二:用变量(诶,这题好像前面做过了,当复习吧)
select r1.* from (select (@i:=case when @couIdFlow=t1.couId then @i+1 else 1 end) as number,(@couIdFlow:=t1.couId) as 'couId',t1.stuId,t1.score from (select @i:=0,@couIdFlow:=1) as var cross join stuScore as t1 order by t1.couId asc,t1.score desc)as r1 where r1.number between 1 and 2;
#还有一位大佬写的方法:很精妙
select a.s_id,a.c_id,a.s_score from score a
where (select COUNT(1) from score b where b.c_id=a.c_id and b.s_score>=a.s_score)<=2 order by a.c_id
源头:https://www.cnblogs.com/kangxinxin/p/11585935.html
题43:统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列, 若人数相同,按课程号升序排列
#这道题咋一看有点重复的感觉,是多道题的结合体,也不难
#直观点的方法,题目甚至没说要进行所谓的显示课程名称
select t1.couId,count(*) as 'all'
from stuScore as t1
group by t1.couId
having count(*)>5
order by count(*)desc,t1.couId asc;
#优化一点可视性
#--在优化的过程中,发现
#group by 后面的字段最好还是跟靠近from的表对奇的好
select t1.couId,course.couName,count(*) as 'all'
,group_concat(t1.stuId order by t1.stuId) as 'stuId'
from stuScore as t1
left join course
on t1.couId=course.couId
group by t1.couId
having count(*)>5
order by count(*)desc,t1.couId asc;
题44:检索至少选修两门课程的学生学号
#你有选修,那一定就在stuScore的表里面有内容啊,是不是?
select stuId from stuScore group by stuId having count(*)>=2;
#没有学生信息?优化一下
select student.* from stuScore left join student on student.stuId=stuScore.stuId group by stuId having count(*)>=2;
题45:查询选修了全部课程的学生信息
#使用从course表获取课程总数是比直接输入数字好的
#在灵活性上提升,因为如果增加课程呢?是不是?
select student.*
from stuScore
left join student
on student.stuId=stuScore.stuId
group by stuId
having count(*)=(select count(*) from course);
题46:查询各学生的年龄
#其实如果懂时间日期函数的话,是不难的
#函数timestampdiff-timestamp:时间戳-diff:差距
select student.*,
timestampdiff(year,student.stuDate,now()) as 'age'
from student;
#更加精细一点,不到月和日的话不算一岁
#比如2020,8,1现在2022,7,30虽然2022-2020=2,但是还没到只能算一
select student.*,
(
case when
( month(student.stuDate)>month(now())
or
( month(student.stuDate)=month(now())
and day(student.stuDate)>day(now())
)
)
and
timestampdiff(year,student.stuDate,now())>0
then
timestampdiff(year,student.stuDate,now())-1
else
timestampdiff(year,student.stuDate,now()) end) as 'age'
from student;
题47、查询本周过生日的学生
#以前学过点java和C,对数值比较敏感
#这里用dayofweek的方法会返回一个数值
#西方那边的计日不太一样,是这样子的 周日是1,周一是2,周六是7
select student.* from student cross join
(select dayofweek(curdate()) as wekNum1) t1
where stuDate between
date_sub(curdate(), INTERVAL dayofweek(curdate())-2 day) and date_add(curdate(), INTERVAL (dayofweek(curdate())-7-1)*(-1) day);
#解释一下between里面的数值采用
#我们返回的数字为准要回到星期一,即总是需要curdate-2
#要走到星期日,即总是需要7-curdate+1,后面发现总是出错,-(-7+curdate-1)
题48:查询下周过生日的学生
#在明白47题的情况下,在判断条件体里面加7不久好咯?
#事实也是这样子的
select student.* from student
where stuDate between
date_sub(curdate(), INTERVAL dayofweek(curdate())+7-2 day) and date_add(curdate(), INTERVAL (dayofweek(curdate())-7-7-1)*(-1) day);
题49:查询本月过生日的学生
#月份方面的计数还是没什么变化,更简单
#因为不用担心“周日是哪个周的周日的问题”
#一月就是1,十二月就是12
select student.*
from student
where month(student.stuDate)= month(curdate());
##--------------
#突然想了一下,用那个“周”的题目是不是也可以算月啊,试一下
select student.* from student cross join
(select dayofweek(curdate()) as wekNum1) t1
where stuDate between
date_sub(curdate(), INTERVAL dayofmonth(curdate())-1 day) and LAST_DAY(curdate());
题50:查询下月过生日的学生
#下个月就要考虑12+1=13的问题了
select student.*
from student
where month(student.stuDate)= (month(curdate())+1)mod 12;
#突然想了一下,用那个“周”的题目是不是也可以算月啊,试一下