源于知乎: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的更多相关文章

  1. mysql sql优化实例

    mysql sql优化实例 优化前: pt-query-degist分析结果: # Query 3: 0.00 QPS, 0.00x concurrency, ID 0xDC6E62FA021C85B ...

  2. jbpm3.2中jbpm.jpdl.mysql.sql文件运行报错的问题

    这是一个很久之前遇到的问题,就是用从官网下下载的jbpm组件,它的jbpm.jpdl.mysql.sql不能正常运行.其原因是该sql文件中有一句语句有错误.现在附上正确的jbpm.jpdl.mysq ...

  3. 程序员实用的 MySQL sql 语句

    这儿只讲究实用,  程序员编程时常用到的 MySQL的 sql语句(不包括基本的 select, update, delete 等语句). 1. 添加一个用户build,并赋予所有权限的命令 gran ...

  4. Atitit.软件GUIbutton与仪表盘--db数据库区--导入mysql sql错误的解决之道

    Atitit.软件GUIbutton与仪表盘--db数据库区--导入mysql sql错误的解决之道 Keyword::截取文本文件后部分 查看提示max_allowed_packet限制 Targe ...

  5. mysql sql语句大全(转载)

      1.说明:创建数据库 CREATE DATABASE database-name 2.说明:删除数据库 drop database dbname 3.说明:备份sql server --- 创建 ...

  6. 从运维的角度分析使用阿里云数据库RDS的必要性--你不应该在阿里云上使用自建的MySQL/SQL Server/Oracle/PostgreSQL数据库

    开宗明义,你不应该在阿里云上使用自建的MySQL or SQL Server数据库,对了,还有Oracle or PostgreSQL数据库. 云数据库 RDS(Relational Database ...

  7. Mysql SQL Mode详解

    Mysql SQL Mode简介 MySQL服务器能够工作在不同的SQL模式下,并能针对不同的客户端以不同的方式应用这些模式.这样,应用程序就能对服务器操作进行量身定制以满足自己的需求.这类模式定义了 ...

  8. [WeChall] Training: MySQL I (MySQL, Exploit, Training)

    Training: MySQL I (MySQL, Exploit, Training) MySQL Authentication Bypass - The classic This one is t ...

  9. MYSQL SQL语句技巧初探(一)

    MYSQL SQL语句技巧初探(一) 本文是我最近了解到的sql某些方法()组合实现一些功能的总结以后还会更新: rand与rand(n)实现提取随机行及order by原理的探讨. Bit_and, ...

随机推荐

  1. 第11组 Alpha事后诸葛亮

    第11组 Alpha事后诸葛亮   组长博客链接 https://www.cnblogs.com/xxylac/p/11924846.html 设想和目标 我们的软件要解决什么问题?是否定义得很清楚? ...

  2. ubantu 安装boost库 c++connector

    安装libmysqlcppconn: sudo apt-get install libmysqlcppconn-dev 安装libboost: sudo apt-get install libboos ...

  3. 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. ...

  4. 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)

  5. Java同步数据结构之PriorityBlockingQueue

    前言 接下来继续BlockingQueue的另一个实现,优先级阻塞队列PriorityBlockingQueue.PriorityBlockingQueue是一个无限容量的阻塞队列,由于容量是无限的所 ...

  6. Android 显示系统:OpenGL简介和Gralloc代码分析

    一.OpenGL ES与EGL Android的GUI系统是基于OpenGL/EGL来实现的. 由于OpenGL是通用函数库,在不同平台系统上需要被“本土化”——把它与具体平台的窗口系统建立起关联,F ...

  7. kotlin 类的委托

    fun main(arg: Array<String>) { val baseImpl = baseImpl() demo(baseImpl).printL() } interface b ...

  8. 18 Flutter仿京东商城项目 商品详情顶部tab切换 顶部下拉菜单 底部浮动导航

    ProductContent.dart import 'package:flutter/material.dart'; import '../services/ScreenAdaper.dart'; ...

  9. 01-02 Flutter仿京东商城项目 功能分析、底部导航Tab切换以及路由配置、架构搭建:(Flutter仿京东商城项目 首页布局以及不同终端屏幕适配方案)

    Flutter和Dart交流学习群:交流群:452892873 01Flutter仿京东商城项目 功能分析.底部导航Tab切换以及路由配置.架构搭建 02Flutter仿京东商城项目 首页布局以及不同 ...

  10. CPU密集型、IO密集型

    CPU密集型(CPU-bound) CPU密集型也叫计算密集型,指的是系统的硬盘.内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/ ...