MySQL SQL Training
源于知乎:50道SQL练习题
一、表数据
1、学生表——Student
create table Student(SId varchar(10),Sname varchar(10),Sage datetime,Ssex varchar(10)); insert into Student values('01' , '赵雷' , '1990-01-01' , '男'); insert into Student values('02' , '钱电' , '1990-12-21' , '男'); insert into Student values('03' , '孙风' , '1990-05-20' , '男'); insert into Student values('04' , '李云' , '1990-08-06' , '男'); insert into Student values('05' , '周梅' , '1991-12-01' , '女'); insert into Student values('06' , '吴兰' , '1992-03-01' , '女'); insert into Student values('07' , '郑竹' , '1989-07-01' , '女'); insert into Student values('09' , '张三' , '2017-12-20' , '女'); insert into Student values('10' , '李四' , '2017-12-25' , '女'); insert into Student values('11' , '李四' , '2017-12-30' , '女'); insert into Student values('12' , '赵六' , '2017-01-01' , '女'); insert into Student values('13' , '孙七' , '2018-01-01' , '女');
2、科目表——Course
create table Course(CId varchar(10),Cname nvarchar(10),TId varchar(10)) insert into Course values('01' , '语文' , '02'); insert into Course values('02' , '数学' , '01'); insert into Course values('03' , '英语' , '03');
3、教师表——Teacher
create table Teacher(TId varchar(10),Tname varchar(10)) insert into Teacher values('01' , '张三'); insert into Teacher values('02' , '李四'); insert into Teacher values('03' , '王五');
4、成绩表——SC
create table SC(SId varchar(10),CId varchar(10),score decimal(18,1)); insert into SC values('01' , '01' , 80); insert into SC values('01' , '02' , 90); insert into SC values('01' , '03' , 99); insert into SC values('02' , '01' , 70); insert into SC values('02' , '02' , 60); insert into SC values('02' , '03' , 80); insert into SC values('03' , '01' , 80); insert into SC values('03' , '02' , 80); insert into SC values('03' , '03' , 80); insert into SC values('04' , '01' , 50); insert into SC values('04' , '02' , 30); insert into SC values('04' , '03' , 20); insert into SC values('05' , '01' , 76); insert into SC values('05' , '02' , 87); insert into SC values('06' , '01' , 31); insert into SC values('06' , '03' , 34); insert into SC values('07' , '02' , 89); insert into SC values('07' , '03' , 98);
二、SQL练习题
1. 查询同时存在" 01 "课程和" 02 "课程的情况
/*只列出学生ID和课程情况*/ select t1.SId,t1.score as score01,t2.score as score02 from (select SId,score from sc where CId='01') as t1, (select SId, score from sc where CId='02') as t2 where t1.SId=t2.SId; +------+---------+---------+ | SId | score01 | score02 | +------+---------+---------+ | 01 | 80.0 | 90.0 | | 02 | 70.0 | 60.0 | | 03 | 80.0 | 80.0 | | 04 | 50.0 | 30.0 | | 05 | 76.0 | 87.0 | +------+---------+---------+ 5 rows in set (0.00 sec)
改进一下:
select sc1.sid,sc1.cid cid01,sc1.score score01,sc2.cid cid02,sc2.score score02 from sc sc1 join sc sc2 on sc1.sid=sc2.sid and sc1.cid="01" and sc2.cid="02"; +------+-------+---------+-------+---------+ | sid | cid01 | score01 | cid02 | score02 | +------+-------+---------+-------+---------+ | 01 | 01 | 80.0 | 02 | 90.0 | | 02 | 01 | 70.0 | 02 | 60.0 | | 03 | 01 | 80.0 | 02 | 80.0 | | 04 | 01 | 50.0 | 02 | 30.0 | | 05 | 01 | 76.0 | 02 | 87.0 | +------+-------+---------+-------+---------+ 5 rows in set (0.00 sec)
如果在此基础上列出更多关于学生的信息:
/*同时列出相关学生的信息*/ select t1.SId,t1.score as score01,t2.score as score02,t3.* from (select SId,score from sc where CId='01') as t1, (select SId, score from sc where CId='02') as t2, Student as t3 where t1.SId=t2.SId and t1.SId=t3.SId; +------+---------+---------+------+-------+---------------------+------+ | SId | score01 | score02 | SId | Sname | Sage | Ssex | +------+---------+---------+------+-------+---------------------+------+ | 01 | 80.0 | 90.0 | 01 | 赵雷 | 1990-01-01 00:00:00 | 男 | | 02 | 70.0 | 60.0 | 02 | 钱电 | 1990-12-21 00:00:00 | 男 | | 03 | 80.0 | 80.0 | 03 | 孙风 | 1990-05-20 00:00:00 | 男 | | 04 | 50.0 | 30.0 | 04 | 李云 | 1990-08-06 00:00:00 | 男 | | 05 | 76.0 | 87.0 | 05 | 周梅 | 1991-12-01 00:00:00 | 女 | +------+---------+---------+------+-------+---------------------+------+ 5 rows in set (0.00 sec)
1.1 查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数
在“同时存在01课程和02课程”的基础上,添加一个条件即可:
select t1.SId,t1.score as score01,t2.score as score02,t3.*
from (select SId,score from sc where CId='01') as t1,(select SId, score from sc where CId='02') as t2,Student as t3
where t1.SId=t2.SId and t1.score>t2.score and t1.SId=t3.SId; +------+---------+---------+------+-------+---------------------+------+ | SId | score01 | score02 | SId | Sname | Sage | Ssex | +------+---------+---------+------+-------+---------------------+------+ | 02 | 70.0 | 60.0 | 02 | 钱电 | 1990-12-21 00:00:00 | 男 | | 04 | 50.0 | 30.0 | 04 | 李云 | 1990-08-06 00:00:00 | 男 | +------+---------+---------+------+-------+---------------------+------+ 2 rows in set (0.00 sec)
1.2 查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null )
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/*只列出学生ID*/ select * from (select SId ,score from sc where sc.CId='01')as t1 left join (select SId ,score from sc where sc.CId='02') as t2 on t1.SId=t2.SId; /*列出学生具体信息*/ select t1.SId,t1.score as score01,t2.score as score02,t3.* from (select SId,score from sc where CId='01') as t1 left join (select SId, score from sc where CId='02') as t2 on t1.SId=t2.SId,Student as t3 where t1.SId=t3.SId;
结果如下:
1.3 查询不存在" 01 "课程但存在" 02 "课程的情况
select * from sc where SId not in (select Sid from sc where CId='01') and CId='02';
2. 查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
/*第一种*/ select t1.SId,t2.Sname,t1.avg from (select SId,AVG(score) as avg from sc group by SId having avg>=60) as t1,student as t2 where t1.SId=t2.SId; /*第二种*/ select student.*,t1.avgscore from student inner JOIN( select sc.SId ,AVG(sc.score)as avgscore from sc GROUP BY sc.SId HAVING AVG(sc.score)>=60)as t1 on student.SId=t1.SId;
3. 查询在 SC 表存在成绩的学生信息
/*第一种*/ select * from Student where SId in (Select SId from sc group by SId); /*第二种*/ select DISTINCT student.* from student ,sc where student.SId=sc.SId; /*第三种*/ select * from Student where SId in (Select DISTINCT SId from sc);
4. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
/*第一种*/ select stu.SId,stu.Sname,t1.NumCourse,t1.SumCourse from Student as stu left join (select SId, count(CId) as NumCourse,sum(score) as SumCourse from sc group by SId) as t1 on stu.SId=t1.SId;
4.1 查看有成绩的学生信息
/*第一种*/ select * from student where SId in (select distinct SId from sc); /*第二种*/ select * from student where EXISTS(select * from sc where student.SId=sc.SId);
5. 查询「李」姓老师的数量
/*第一种*/ select count(*) from teacher where Tname like "李%";
6. 查询学过「张三」老师授课的同学的信息
/*第一种,嵌套查询,略复杂*/ select * from Student where SId in (select SId from sc where CId in (select course.CId from course,teacher where course.TId=teacher.TId and teacher.Tname="张三")); /*第二种*/ select student.* from teacher ,course ,student,sc where teacher.Tname='张三' and teacher.TId=course.TId and course.CId=sc.CId and sc.SId=student.SId;
7. 查询没有学全所有课程的同学的信息
/*第一种*/ /*先找出休全了所有课的学生的ID*/ select * from student where SId not in ( select SId from sc group by SId having count(CId)=(select count(CId) from course));
8. 查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息
/*第一种*/ /*01号学生列不列都可以*/ select * from student where SId in (select distinct SId from sc where CId in (select distinct CId from sc where SId="01") and SId!="01") ;
9. 查询和" 01 "号的同学学习的课程完全相同的其他同学的信息
/*第一种*/ /*sql过长的原因在于,同一个子查询(即t1,t2是同一个子查询),我不得不写两遍,没有找到好的解决方法*/ select * from student where SId!="01" and SId in ( select t1.SId from ( select SId,group_concat(CId order by CId desc) allcourse from sc group by SId order by SId asc ) as t1 where md5(t1.allcourse)=( select md5(t2.allcourse2) from ( select SId,group_concat(CId order by CId desc) allcourse2 from sc group by SId order by SId asc ) as t2 where SId="01" ) ) /*第二种*/ select * from student where student.SId !='01'and student.SId not in ( select t1.SId from ( select student.SId,t.CId from student ,(select sc.CId from sc where sc.SId='01') as t )as t1 left join sc on t1.SId=sc.SId and t1.CId=sc.CId where sc.CId is null ); +------+-------+---------------------+------+ | SId | Sname | Sage | Ssex | +------+-------+---------------------+------+ | 02 | 钱电 | 1990-12-21 00:00:00 | 男 | | 03 | 孙风 | 1990-05-20 00:00:00 | 男 | | 04 | 李云 | 1990-08-06 00:00:00 | 男 | +------+-------+---------------------+------+ 3 rows in set (0.00 sec)
10. 查询没学过"张三"老师讲授的任一门课程的学生姓名
/*第一种*/ select distinct * from student as stu where stu.SId not in ( select SId from sc where CId in (select CId from course where TId=( select TId from teacher where Tname="张三"))) ; /*第二种*/ select * from student where student.SId not in ( select student.SId from student left join sc on student.SId=sc.SId where EXISTS ( select * from teacher ,course where teacher.Tname='张三' and teacher.TId=course.TId and course.CId=sc.CId ) )
11. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
/*第一种*/ select t.SId,student.Sname,t.avgScore from student,(select SId,count(CId) as numCourse,avg(score) as avgScore from sc where score<60 group by SId) as t where t.SId=student.SId and numCourse>=2; /*第二种*/ select student.SId,student.Sname,avg(sc.score) from student ,sc where student.SId=sc.SId and sc.score<60 GROUP BY sc.SId HAVING count(*)>=2;
12. 检索" 01 "课程分数小于 60,按分数降序排列的学生信息
select stu.*,sc.score from student stu,sc where stu.SId=sc.SId and CId="01" and score<60 order by score desc;
13. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
/*第一种*/ /*这里在order前加不加group by,结果都一样*/ select sc.*,t.avg from sc ,(select SId,avg(score) avg from sc group by SId) as t where sc.SId=t.SId order by t.avg desc; /*第二种*/ select sc.SId,sc.CId,sc.score,t1.avgscore from sc left join (select sc.SId,avg(sc.score) as avgscore from sc GROUP BY sc.SId) as t1 on sc.SId =t1.SId ORDER BY t1.avgscore DESC;
14. 查询各科成绩最高分、最低分和平均分:
以如下形式显示:
课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
/*注意group by,order by的位置,很困惑,与select要对应*/ select sc.CId ,co.Cname, max(sc.score)as 最高分, min(sc.score)as 最低分,AVG(sc.score)as 平均分, count(*)as 选修人数,sum(case when sc.score>=60 then 1 else 0 end )/count(*)as 及格率, sum(case when sc.score>=70 and sc.score<80 then 1 else 0 end )/count(*)as 中等率, sum(case when sc.score>=80 and sc.score<90 and sc.score<80 then 1 else 0 end )/count(*)as 优良率, sum(case when sc.score>=90 then 1 else 0 end )/count(*)as 优秀率 from sc left join course as co on sc.CId=co.CId GROUP BY sc.CId ORDER BY count(*)DESC,sc.CId asc
15. 按各科成绩进行排序,并显示排名。(三种形式都来一遍)(此时我新添加了2个学生的各三门成绩)
15.1 相同的score,rank不重复,按sid排名。所有的rank是连续的。(1,2,3)
from中的t表是为了变量初始化而无需单独的SET命令。
第二个when的条件总是true。
select sc.SId,sc.CId,sc.score, case when @pre_parent_code=sc.CId then @curRank:=@curRank+1 when @pre_parent_code:=sc.CId then @curRank:=1 end as rank from (select @curRank:=0,@pre_parent_code:='') as t ,sc ORDER by sc.CId,sc.score desc; +------+------+-------+------+ | SId | CId | score | rank | +------+------+-------+------+ | 01 | 01 | 80.0 | 1 | | 03 | 01 | 80.0 | 2 | | 05 | 01 | 76.0 | 3 | | 02 | 01 | 70.0 | 4 | | 09 | 01 | 70.0 | 5 | | 04 | 01 | 50.0 | 6 | | 06 | 01 | 31.0 | 7 | | 10 | 01 | 31.0 | 8 | | 01 | 02 | 90.0 | 1 | | 10 | 02 | 90.0 | 2 | | 07 | 02 | 89.0 | 3 | | 05 | 02 | 87.0 | 4 | | 03 | 02 | 80.0 | 5 | | 02 | 02 | 60.0 | 6 | | 04 | 02 | 30.0 | 7 | | 09 | 02 | 30.0 | 8 | | 01 | 03 | 99.0 | 1 | | 09 | 03 | 99.0 | 2 | | 07 | 03 | 98.0 | 3 | | 02 | 03 | 80.0 | 4 | | 03 | 03 | 80.0 | 5 | | 06 | 03 | 34.0 | 6 | | 04 | 03 | 20.0 | 7 | | 10 | 03 | 20.0 | 8 | +------+------+-------+------+ 24 rows in set (0.00 sec)
15.2 相同的Score,rank相同,而且所有rank是有间断的(例如第一和第二分数相同,那么前三名的rank为1,1,3)
这种排序应该是实际中会采纳的排序。
这种形式的排序比较好理解,self-join,找出另一个表中同组中值比自己大的行数,那自己的排名就是count+1,间断也是自动产生了。
select sc.SId,sc.CId,sc.score,tp.rank from sc left join (select SId, CId, (select count(sc2.score)+1 from sc sc2 where sc1.CId=sc2.CId and sc2.score>sc1.score) rank from sc sc1) tp on sc.SId=tp.SId and sc.CId=tp.CId order by sc.CId, rank +------+------+-------+------+ | SId | CId | score | rank | +------+------+-------+------+ | 01 | 01 | 80.0 | 1 | | 03 | 01 | 80.0 | 1 | | 05 | 01 | 76.0 | 3 | | 02 | 01 | 70.0 | 4 | | 09 | 01 | 70.0 | 4 | | 04 | 01 | 50.0 | 6 | | 06 | 01 | 31.0 | 7 | | 10 | 01 | 31.0 | 7 | | 01 | 02 | 90.0 | 1 | | 10 | 02 | 90.0 | 1 | | 07 | 02 | 89.0 | 3 | | 05 | 02 | 87.0 | 4 | | 03 | 02 | 80.0 | 5 | | 02 | 02 | 60.0 | 6 | | 04 | 02 | 30.0 | 7 | | 09 | 02 | 30.0 | 7 | | 01 | 03 | 99.0 | 1 | | 09 | 03 | 99.0 | 1 | | 07 | 03 | 98.0 | 3 | | 02 | 03 | 80.0 | 4 | | 03 | 03 | 80.0 | 4 | | 06 | 03 | 34.0 | 6 | | 04 | 03 | 20.0 | 7 | | 10 | 03 | 20.0 | 7 | +------+------+-------+------+ 24 rows in set (0.00 sec)
经过自己对其它的参考,竟然改出一个简单的版本:
select sc2.sid as sid,sc2.cid as cid,sc2.score,if(isnull(sc3.score),1,count(*)+1) as rank from sc sc2 left join sc sc3 on sc3.CId=sc2.CId and sc2.score<sc3.score group by sc2.cid,sc2.sid order by cid,score desc;
/*相比其它,我新插入了两个学生的供6条成绩*/ +------+------+-------+------+ | sid | cid | score | rank | +------+------+-------+------+ | 01 | 01 | 80.0 | 1 | | 03 | 01 | 80.0 | 1 | | 05 | 01 | 76.0 | 3 | | 02 | 01 | 70.0 | 4 | | 09 | 01 | 70.0 | 4 | | 04 | 01 | 50.0 | 6 | | 06 | 01 | 31.0 | 7 | | 10 | 01 | 31.0 | 7 | | 01 | 02 | 90.0 | 1 | | 10 | 02 | 90.0 | 1 | | 07 | 02 | 89.0 | 3 | | 05 | 02 | 87.0 | 4 | | 03 | 02 | 80.0 | 5 | | 02 | 02 | 60.0 | 6 | | 04 | 02 | 30.0 | 7 | | 09 | 02 | 30.0 | 7 | | 09 | 03 | 99.0 | 1 | | 01 | 03 | 99.0 | 1 | | 07 | 03 | 98.0 | 3 | | 02 | 03 | 80.0 | 4 | | 03 | 03 | 80.0 | 4 | | 06 | 03 | 34.0 | 6 | | 04 | 03 | 20.0 | 7 | | 10 | 03 | 20.0 | 7 | +------+------+-------+------+ 24 rows in set (0.00 sec)
15.3 相同的Score,rank相同,但是所有rank连续(第一第二分数相同,前四名1,1,2,3)
首先,这种排序是不科学的。
方法就是在上一题的基础上,在进行self-join时,添加"distinct",去重即可。比如第三名,因为统计时有两个值比自己大,但是不管有几个相同的值比自己大,自己的rank都是2,用count(distinct col)+1就可以做到。
/*001*/ select sc.SId,sc.CId,sc.score,tp.rank from sc left join ( select SId, CId, ( select count(distinct sc2.score)+1 from sc sc2 where sc1.CId=sc2.CId and sc2.score>sc1.score ) rank from sc sc1 ) tp on sc.SId=tp.SId and sc.CId=tp.CId order by sc.CId, rank /*002*/ select sc2.sid as sid,sc2.cid as cid,sc2.score,if(isnull(sc3.score),1,count(distinct sc3.score)+1) as rank from sc sc2 left join sc sc3 on sc3.CId=sc2.CId and sc2.score<sc3.score group by sc2.cid,sc2.sid order by cid,score desc; +------+------+-------+------+ | sid | cid | score | rank | +------+------+-------+------+ | 03 | 01 | 80.0 | 1 | | 01 | 01 | 80.0 | 1 | | 05 | 01 | 76.0 | 2 | | 09 | 01 | 70.0 | 3 | | 02 | 01 | 70.0 | 3 | | 04 | 01 | 50.0 | 4 | | 06 | 01 | 31.0 | 5 | | 10 | 01 | 31.0 | 5 | | 01 | 02 | 90.0 | 1 | | 10 | 02 | 90.0 | 1 | | 07 | 02 | 89.0 | 2 | | 05 | 02 | 87.0 | 3 | | 03 | 02 | 80.0 | 4 | | 02 | 02 | 60.0 | 5 | | 04 | 02 | 30.0 | 6 | | 09 | 02 | 30.0 | 6 | | 01 | 03 | 99.0 | 1 | | 09 | 03 | 99.0 | 1 | | 07 | 03 | 98.0 | 2 | | 02 | 03 | 80.0 | 3 | | 03 | 03 | 80.0 | 3 | | 06 | 03 | 34.0 | 4 | | 10 | 03 | 20.0 | 5 | | 04 | 03 | 20.0 | 5 | +------+------+-------+------+ 24 rows in set (0.00 sec)
16. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺(1,1,3)
select sc1.sid,sc1.sum,if(isnull(sc2.sum),1,count(sc2.sum)+1) rank from (select sid,sum(score) as sum from sc group by sid) as sc1 left join (select sid,sum(score) as sum from sc group by sid) as sc2 on sc1.sum<sc2.sum group by sc1.sid order by rank asc +------+-------+------+ | sid | sum | rank | +------+-------+------+ | 01 | 269.0 | 1 | | 03 | 240.0 | 2 | | 02 | 210.0 | 3 | | 09 | 199.0 | 4 | | 07 | 187.0 | 5 | | 05 | 163.0 | 6 | | 10 | 141.0 | 7 | | 04 | 100.0 | 8 | | 06 | 65.0 | 9 | +------+-------+------+ 9 rows in set (0.00 sec)
16.1 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺(1,1,2)
在上题基础上添加distinct即可。
select sc1.sid,sc1.sum,if(isnull(sc2.sum),1,count(distinct sc2.sum)+1) rank from (select sid,sum(score) as sum from sc group by sid) as sc1 left join (select sid,sum(score) as sum from sc group by sid) as sc2 on sc1.sum<sc2.sum group by sc1.sid order by rank asc
(因为上几道排序的题,我在成绩表中添加了6行新的数据,这里再改回去,原表只有18行)
rename table sc to st; rename table scback to sc;
17. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
select course.CId,course.Cname,t1.* from course LEFT JOIN ( select sc.CId, sum(case when sc.score>=85 and sc.score<=100 then 1 else 0 end ) as '[85-100] Number', CONCAT(sum(case when sc.score>=85 and sc.score<=100 then 1 else 0 end )/count(*)*100,'%') as '[85-100]', sum(case when sc.score>=70 and sc.score<85 then 1 else 0 end ) as '[70-85) Number', CONCAT(sum(case when sc.score>=70 and sc.score<85 then 1 else 0 end )/count(*)*100,'%') as '[70-85)', sum(case when sc.score>=60 and sc.score<70 then 1 else 0 end ) '[60-70) Number', CONCAT(sum(case when sc.score>=60 and sc.score<70 then 1 else 0 end )/count(*)*100,'%') as '[60-70)', sum(case when sc.score>=0 and sc.score<60 then 1 else 0 end ) as '[0-60) Number', CONCAT(sum(case when sc.score>=0 and sc.score<60 then 1 else 0 end )/count(*)*100,'%') as '[0-60)' from sc GROUP BY sc.CId ) as t1 on course.CId=t1.CId
18. 查询各科成绩前三名的记录
这里的前三名,有一定的歧义:
如果某科成绩如“100,100,95,95,90,90,88,...”,前三名是应该是指成绩为90,95,100的人6个学生?还是只有“100,90”的4个?
如果某科成绩为““100,100,100,95,95,90,90,88,...”,前三名是成绩为100的3个学生?还是成绩为“100,95,90”的7个学生?
select CId, SId, score from sc where (select count(*) from sc sc1 where sc1.CId=sc.CId and sc1.score>sc.score) <3 order by CId, score desc
19. 查询每门课程被选修的学生数
select course.*,t.count from course left join (select cid,count(sid) as count from sc group by cid) as t on course.cid=t.cid;
20. 查询出只选修两门课程的学生学号和姓名
select sid,sname from student where sid in(select sid from sc group by sid having count(cid)=2);
21. 查询男生、女生人数
select ssex,count(sid) from student group by ssex;
22. 查询名字中含有「风」字的学生信息
select * from student where sname like'%风%';
23. 查询同名同性学生名单,并统计同名人数
select s.sid,s.sname,s.ssex,count(*) from student as s join student as t on s.sname=t.sname and s.ssex=t.ssex and s.sid!=t.sid group by sid with rollup; +------+-------+------+----------+ | sid | sname | ssex | count(*) | +------+-------+------+----------+ | 10 | 李四 | 女 | 1 | | 11 | 李四 | 女 | 1 | | NULL | 李四 | 女 | 2 | +------+-------+------+----------+
24. 查询 1990 年出生的学生名单
select * from student where year(sage)=1990;
25. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
select cid, avg(score) as avg from sc group by cid order by avg desc; +------+----------+ | cid | avg | +------+----------+ | 02 | 72.66667 | | 03 | 68.50000 | | 01 | 64.50000 | +------+----------+ select c.*,t.avg as avg from course as c join (select cid, avg(score) as avg from sc group by cid) as t on c.cid=t.cid order by avg desc,cid; +------+-------+------+----------+ | CId | Cname | TId | avg | +------+-------+------+----------+ | 02 | 数学 | 01 | 72.66667 | | 03 | 英语 | 03 | 68.50000 | | 01 | 语文 | 02 | 64.50000 | +------+-------+------+----------+
26. 查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
select stu.* from student as stu where sid in (select sid from sc group by sid having avg(score)>=85); +------+-------+---------------------+------+ | SId | Sname | Sage | Ssex | +------+-------+---------------------+------+ | 01 | 赵雷 | 1990-01-01 00:00:00 | 男 | | 07 | 郑竹 | 1989-07-01 00:00:00 | 女 | +------+-------+---------------------+------+ select stu.*,t.score from student as stu, (select sid,avg(score) as score from sc group by sid having avg(score)>=85) as t where stu.sid=t.sid; +------+-------+---------------------+------+----------+ | SId | Sname | Sage | Ssex | score | +------+-------+---------------------+------+----------+ | 01 | 赵雷 | 1990-01-01 00:00:00 | 男 | 89.66667 | | 07 | 郑竹 | 1989-07-01 00:00:00 | 女 | 93.50000 | +------+-------+---------------------+------+----------+
27. 查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
select sid,sname from student where sid in ( select sid from sc where cid in ( select cid from course where cname="数学"
) and score<60
); +------+-------+ | sid | sname | +------+-------+ | 04 | 李云 | +------+-------+ 1 row in set (0.00 sec)
28. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
select s.sid,s.sname,t.cid,t.score from student as s left join sc as t on s.sid=t.sid order by sid,cid;
29. 查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
select t.sid,s.sname,c.cname,t.score from sc as t,student as s,course as c where t.score>70 and t.cid=c.cid and t.sid=s.sid; +------+-------+-------+-------+ | sid | sname | cname | score | +------+-------+-------+-------+ | 01 | 赵雷 | 语文 | 80.0 | | 01 | 赵雷 | 数学 | 90.0 | | 01 | 赵雷 | 英语 | 99.0 | | 02 | 钱电 | 英语 | 80.0 | | 03 | 孙风 | 语文 | 80.0 | | 03 | 孙风 | 数学 | 80.0 | | 03 | 孙风 | 英语 | 80.0 | | 05 | 周梅 | 语文 | 76.0 | | 05 | 周梅 | 数学 | 87.0 | | 07 | 郑竹 | 数学 | 89.0 | | 07 | 郑竹 | 英语 | 98.0 | +------+-------+-------+-------+
30. 查询不及格的课程(什么意思?平均分不及格?)
select cid,avg(score) from sc group by cid having avg(score)<60;
31. 查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
select sid,sname from student where sid in( select sid from sc where cid=01 and score>80 );
32. 求每门课程的学生人数
select cid ,count(sid) from sc group by cid;
33. 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
这里有多种情况需要考虑。
第一是一个老师只开一门课,那这课最高的分数只会有一个:
/*由于一个老师只开一门课,这里的in可以用=替换*/
select * from sc where cid in (select cid from course where tid=(select tid from teacher where tname="张三") ) order by score desc limit 1; +------+------+-------+ | SId | CId | score | +------+------+-------+ | 01 | 02 | 90.0 | +------+------+-------+ 1 row in set (0.00 sec)
骑士这里利用排序和LIMIT来输出是不对的,如果最高成绩有多名学生,那就错了,所以还是要从对cid分组入手,利用max函数找出该门课的最高分,再在成绩表中进行筛选。
第二是一个老师可以开多门课,那每一门课都会存在一个最高成绩,如果只是输出多门课中的一个最高成绩,那语句与上面情况一样(只是in不能用=替换)。
而如果是每一门课的最高成绩都输出,那么在成绩表sc中找出这个老师的所有课的成绩记录,然后对这个派生表用cid分组,并找出他的每门课的max(score),然后再从成绩表sc入手找出cid相等,score=max(score)的记录。最后连接student表,输出信息与成绩。
34. 成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
上面已经讨论过了!
35. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
这里应该是指同一个学生有不同的课程成绩相同。
select distinct sc.* from sc join sc as t on sc.sid=t.sid and sc.cid!=t.cid and sc.score=t.score;
36. 查询每门功课成绩最好的前两名
(这个取“前两名”可以利用排序和LIMIT解决了)
37. 统计每门课程的学生选修人数(超过 5 人的课程才统计)。
select cid, count(sid) as number from sc group by cid having count(sid)>5; +------+--------+ | cid | number | +------+--------+ | 01 | 6 | | 02 | 6 | | 03 | 6 | +------+--------+ 3 rows in set (0.00 sec)
38. 检索至少选修两门课程的学生学号
select sid ,count(cid) as cNum from sc group by sid having cNum>1;
39. 查询选修了全部课程的学生信息
/*先查询总共共有多少门课*/ select count(distinct cid) from course; +---------------------+ | count(distinct cid) | +---------------------+ | 3 | +---------------------+ /*从成绩表找出满足条件的sid*/ select sid from sc group by sid having count(cid)=(select count(distinct cid) from course); +------+ | sid | +------+ | 01 | | 02 | | 03 | | 04 | +------+ 4 rows in set (0.00 sec)
40. 查询各学生的年龄,只按年份来算
select sid,sname,year(curdate())-year(sage) from student;
41. 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
select student.SId,student.Sname,TIMESTAMPDIFF(YEAR,student.Sage,CURDATE()) as age from student;
关于时间函数 TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2)
这里设置减法计算(expr2-expr1)后的unit为year,结果正好是符号题目的要求的
SELECT TIMESTAMPDIFF(YEAR,'2000-05-05','2002-05-05') as result; +--------+ | result | +--------+ | 2 | +--------+ SELECT TIMESTAMPDIFF(YEAR,'2000-05-05','2002-05-06') as result; +--------+ | result | +--------+ | 2 | +--------+ SELECT TIMESTAMPDIFF(YEAR,'2000-05-05','2002-05-04') as result; +--------+ | result | +--------+ | 1 | +--------+
42. 查询本周过生日的学生
select * from student where week(sage)=week(now()); Empty set (0.00 sec)
43. 查询下周过生日的学生
select * from student where week(sage)=week(now())+1; Empty set (0.00 sec)
44. 查询本月过生日的学生
select * from student where month(sage)=month(now()); Empty set (0.00 sec)
45. 查询下月过生日的学生
select * from student where month(sage)=month(now())+1;