Bootstrap

Finished-MySQL-50道-经典测试题

MySQL-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;
 #突然想了一下,用那个“周”的题目是不是也可以算月啊,试一下
 
 
 
;