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('' , '赵雷' , '1990-01-01' , '男');
insert into Student values('' , '钱电' , '1990-12-21' , '男');
insert into Student values('' , '孙风' , '1990-05-20' , '男');
insert into Student values('' , '李云' , '1990-08-06' , '男');
insert into Student values('' , '周梅' , '1991-12-01' , '女');
insert into Student values('' , '吴兰' , '1992-03-01' , '女');
insert into Student values('' , '郑竹' , '1989-07-01' , '女');
insert into Student values('' , '张三' , '2017-12-20' , '女');
insert into Student values('' , '李四' , '2017-12-25' , '女');
insert into Student values('' , '李四' , '2017-12-30' , '女');
insert into Student values('' , '赵六' , '2017-01-01' , '女');
insert into Student values('' , '孙七' , '2018-01-01' , '女');
2、科目表——Course
create table Course(CId varchar(10),Cname nvarchar(10),TId varchar(10))
insert into Course values('' , '语文' , '');
insert into Course values('' , '数学' , '');
insert into Course values('' , '英语' , '');
3、教师表——Teacher
create table Teacher(TId varchar(10),Tname varchar(10))
insert into Teacher values('' , '张三');
insert into Teacher values('' , '李四');
insert into Teacher values('' , '王五');
4、成绩表——SC
create table SC(SId varchar(10),CId varchar(10),score decimal(18,1));
insert into SC values('' , '' , 80);
insert into SC values('' , '' , 90);
insert into SC values('' , '' , 99);
insert into SC values('' , '' , 70);
insert into SC values('' , '' , 60);
insert into SC values('' , '' , 80);
insert into SC values('' , '' , 80);
insert into SC values('' , '' , 80);
insert into SC values('' , '' , 80);
insert into SC values('' , '' , 50);
insert into SC values('' , '' , 30);
insert into SC values('' , '' , 20);
insert into SC values('' , '' , 76);
insert into SC values('' , '' , 87);
insert into SC values('' , '' , 31);
insert into SC values('' , '' , 34);
insert into SC values('' , '' , 89);
insert into SC values('' , '' , 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='') as t1,
(select SId, score from sc where CId='') 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='') as t1,
(select SId, score from sc where CId='') 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='') as t1,(select SId, score from sc where CId='') 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 )
/*只列出学生ID*/
select * from (select SId ,score from sc where sc.CId='')as t1
left join (select SId ,score from sc where sc.CId='') 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='') as t1 left join (select SId, score from sc where CId='') 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='') and CId='';
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 !=''and student.SId not in (
select t1.SId
from (
select student.SId,t.CId
from student ,(select sc.CId from sc where sc.SId='') 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就可以做到。
/**/
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 /**/
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;
MySQL SQL Training的更多相关文章
- mysql sql优化实例
mysql sql优化实例 优化前: pt-query-degist分析结果: # Query 3: 0.00 QPS, 0.00x concurrency, ID 0xDC6E62FA021C85B ...
- jbpm3.2中jbpm.jpdl.mysql.sql文件运行报错的问题
这是一个很久之前遇到的问题,就是用从官网下下载的jbpm组件,它的jbpm.jpdl.mysql.sql不能正常运行.其原因是该sql文件中有一句语句有错误.现在附上正确的jbpm.jpdl.mysq ...
- 程序员实用的 MySQL sql 语句
这儿只讲究实用, 程序员编程时常用到的 MySQL的 sql语句(不包括基本的 select, update, delete 等语句). 1. 添加一个用户build,并赋予所有权限的命令 gran ...
- Atitit.软件GUIbutton与仪表盘--db数据库区--导入mysql sql错误的解决之道
Atitit.软件GUIbutton与仪表盘--db数据库区--导入mysql sql错误的解决之道 Keyword::截取文本文件后部分 查看提示max_allowed_packet限制 Targe ...
- mysql sql语句大全(转载)
1.说明:创建数据库 CREATE DATABASE database-name 2.说明:删除数据库 drop database dbname 3.说明:备份sql server --- 创建 ...
- 从运维的角度分析使用阿里云数据库RDS的必要性--你不应该在阿里云上使用自建的MySQL/SQL Server/Oracle/PostgreSQL数据库
开宗明义,你不应该在阿里云上使用自建的MySQL or SQL Server数据库,对了,还有Oracle or PostgreSQL数据库. 云数据库 RDS(Relational Database ...
- Mysql SQL Mode详解
Mysql SQL Mode简介 MySQL服务器能够工作在不同的SQL模式下,并能针对不同的客户端以不同的方式应用这些模式.这样,应用程序就能对服务器操作进行量身定制以满足自己的需求.这类模式定义了 ...
- [WeChall] Training: MySQL I (MySQL, Exploit, Training)
Training: MySQL I (MySQL, Exploit, Training) MySQL Authentication Bypass - The classic This one is t ...
- MYSQL SQL语句技巧初探(一)
MYSQL SQL语句技巧初探(一) 本文是我最近了解到的sql某些方法()组合实现一些功能的总结以后还会更新: rand与rand(n)实现提取随机行及order by原理的探讨. Bit_and, ...
随机推荐
- 第11组 Alpha事后诸葛亮
第11组 Alpha事后诸葛亮 组长博客链接 https://www.cnblogs.com/xxylac/p/11924846.html 设想和目标 我们的软件要解决什么问题?是否定义得很清楚? ...
- ubantu 安装boost库 c++connector
安装libmysqlcppconn: sudo apt-get install libmysqlcppconn-dev 安装libboost: sudo apt-get install libboos ...
- Change Assembly Version in a compiled .NET assembly
Change Assembly Version in a compiled .NET assembly You can use ILMerge: ILMerge.exe Foo.dll /ver:1. ...
- ExtractIcon function Retrieves a handle to an icon from the specified executable file, DLL, or icon file.
https://msdn.microsoft.com/zh-cn/vstudio/ms648068(v=vs.90)
- Java同步数据结构之PriorityBlockingQueue
前言 接下来继续BlockingQueue的另一个实现,优先级阻塞队列PriorityBlockingQueue.PriorityBlockingQueue是一个无限容量的阻塞队列,由于容量是无限的所 ...
- Android 显示系统:OpenGL简介和Gralloc代码分析
一.OpenGL ES与EGL Android的GUI系统是基于OpenGL/EGL来实现的. 由于OpenGL是通用函数库,在不同平台系统上需要被“本土化”——把它与具体平台的窗口系统建立起关联,F ...
- kotlin 类的委托
fun main(arg: Array<String>) { val baseImpl = baseImpl() demo(baseImpl).printL() } interface b ...
- 18 Flutter仿京东商城项目 商品详情顶部tab切换 顶部下拉菜单 底部浮动导航
ProductContent.dart import 'package:flutter/material.dart'; import '../services/ScreenAdaper.dart'; ...
- 01-02 Flutter仿京东商城项目 功能分析、底部导航Tab切换以及路由配置、架构搭建:(Flutter仿京东商城项目 首页布局以及不同终端屏幕适配方案)
Flutter和Dart交流学习群:交流群:452892873 01Flutter仿京东商城项目 功能分析.底部导航Tab切换以及路由配置.架构搭建 02Flutter仿京东商城项目 首页布局以及不同 ...
- CPU密集型、IO密集型
CPU密集型(CPU-bound) CPU密集型也叫计算密集型,指的是系统的硬盘.内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/ ...