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 )

/*只列出学生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;
View Code

  结果如下:

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;
 
原文地址:https://www.cnblogs.com/bigbigbigo/p/10938356.html