如何以正确地姿势AK SQL查询50题(精华篇)

前言------

AK: ALL Killed

这学期学数据库系统概论,作为一个初学者,必须先熟练掌握SQL的基本查询语句,在完成了老师的SQL50题之后,我把我自己地AK姿势记录下来, 便于回忆之余,也希望对大家有帮助.

"博客要精心雕琢,我是米开朗基罗",  雕琢了两天,然后没保存好,实在是太憋屈了,,,不甘心,现在终于补回来了,可以好好睡了.

自认为是SQL50题查询中最完善的博客,写文章不容易啊,终于知道计算机的书籍为啥都这么贵了....

目录

一.完成这50题之前首先做什么?

二.这50题要怎么做

三.建表并且插入数据

四.给人以鱼,不如授之以渔: 题目精选解析

         五.SQL代码大全(不包括日期的题目)


一.完成这50题之前首先做什么?

1.完成第三章的例题

假如你基础知识还基本没掌握:我建议先把<< 数据库系统概论>>(萨师煊)第三章的例题都好好研究一遍, 关键是要自己敲一遍, 这样做的目的是让你对一些连接,查询,分组,聚集函数,谓词查询,Like,IN,ORDER BY等基础知识 有足够的理解和记忆 ,避免做题时,无技巧可用.

2.理解好GROUP BY

分享一篇超好的博客,一看就领悟(超链接)

3.理解好连接

for(枚举表A中的元组 :i){
    
   for(枚举表B中的元组:j){
   
       for(枚举表C中的元组:k){
         
         if(i ,j,k连接而成的元组满足条件)
           输出i,j,k连接而成的元组
       }
  }
}
注:我只是便于理解写的,实际中,一旦不符合就会contine ,效率比我写的运行方式高多了

4.把中文输入法的符号改为英文符号,这绝对能节省一大半的时间

如何以正确地姿势AK SQL查询50题(精华篇)_第1张图片如何以正确地姿势AK SQL查询50题(精华篇)_第2张图片

上部分的语句和下部分的语句,差别就在箭头处的符号是中文字符.......这种错误有时很难查找,会让你一脸懵逼的,所以建议大家

禁止掉中文符号!!!!!!!! (以搜狗输入法为例)

 

二.这50题要怎么做

我觉得这50题当中,比较有价值的题目,或者说稍微有点难度的题目就那么20题,其余都是比较基础的题目.

1.你不能应付作业的形式来对待....要以提升水平来看待

2.在做题的过程中不要去网上查找题解,这点超级重要!!

3.一道题要尽自己所能去想,时间充足的话,一道题可以给自己一小时的时间去思考,遇到不熟悉的知识,可以翻开课本查询

4.如果一道题有思路,但是觉得可能不好写,不要放弃,尽自己所能去模拟出来, 即使你的思路或者解法不是很优秀,但是在你模拟

的中间过程,你获得了调试能力,对知识点理解得更加熟练,这比一不会就看答案强多了.

5.实在不会的可以问老师,同学,如果都没得问的话,可以查找题解,但是一定要做到是自己的,说白了,不会的这道题,在隔了半个月,你还是会做.

三.建表并且插入数据

环境:PostgreSQL 10 ,命令行模式 (都是用书上基本的SQL语句,可以在mySQL,Sqlite等用)

数据表介绍
--1.学生表
Student(Sno,Sname,Sage,Ssex)
--Sno 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别
--2.课程表
Course(Cno,Cname,Tno)
--Cno 课程编号,Cname 课程名称,Tno 教师编号
--3.教师表
Teacher(Tno,Tname)
--Tno 教师编号,Tname 教师姓名
--4.成绩表
SC(Sno,Cno,Grade)
--Sno 学生编号,Cno 课程编号,Greade 分数

/*
建立Student表,并且插入数据
*/
CREATE TABLE Student(

   Sno CHAR(9),
   Sname CHAR(9),
   Sage date,
   Ssex CHAR(9)
);
insert into Student values('01' , '赵雷' , '1990-01-01' , '男');
insert into Student values('02' , '钱电' , '1990-12-21' , '男');
insert into Student values('03' , '孙风' , '1990-12-20' , '男');
insert into Student values('04' , '李云' , '1990-12-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吴兰' , '1992-01-01' , '女');
insert into Student values('07' , '郑竹' , '1989-01-01' , '女');
insert into Student values('09' , '张三' , '2017-12-20' , '女');
insert into Student values('10' , '李四' , '2017-12-25' , '女');
insert into Student values('11' , '李四' , '2012-06-06' , '女');
insert into Student values('12' , '赵六' , '2013-06-13' , '女');
insert into Student values('13' , '孙七' , '2014-06-01' , '女');
/*
插入Course表和数据
*/

CREATE TABLE Course(

   Cno CHAR(9),
   Cname CHAR(9),
   Tno  CHAR(9)
);

insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');
/*
插入Teacher表和数据
*/
CREATE TABLE Teacher(

   Tno CHAR(9),
   Tname CHAR(9)

);

insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');

 

/*
创建SC表,并且插入数据
*/
CREATE TABLE SC(

  Sno CHAR(9),
  Cno CHAR(9),
  Grade SMALLINT
);
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代码:

SELECT Cno,MAX(Grade) AS 最高分,MIN(Grade) AS 最低分,AVG(Grade) AS 平均分
FROM SC 
GROUP BY Cno;

 

 

  • 类型二:外连接的使用

题目:查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null )

分析:

第一步:先用SC派生出一张只选修01的表 ,x表

第二步:用SC派生出一张只选修02的表,y表

第三步:用x表左外连接y表(题目要求不存在时显示为NULL),这样才能保证选修了01课程的学生都可以输出

SQL代码:

SELECT x.*,y.Cno,y.Grade
FROM   (SELECT *
         FROM SC x
         WHERE Cno ='01'
         )  AS x

         LEFT OUTER JOIN 
         ( SELECT *
           FROM SC 
           WHERE Cno ='02'
         ) AS y ON (x.Sno = y.Sno);

 

 

  • 类型三:通配符的使用

题目: 查询名字中含有「风」字的学生信息

分析: %代表任意个字符

SQL代码:

SELECT *
FROM Student
WHERE Sname LIKE '%风%';



 

  • 类型四.嵌套查询和谓词IN的使用(优点:结构清晰)

题目:查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩

分析:

第一步:我们依次枚举每个学生,

第二步每当我们枚举一个学生,就应该判断该该学会是不是属于"两门及其以上不及格课程的"的学号集合中;

第三步:所以我们要去找出"两门及其以上不及格课程的"的学号集合"

第四步:确定了在上述集合中后,我们认定这个学生应该输出,但是要输出平均成绩怎么办呢?在输出平均成绩的时候,在SELECT中计算平均成绩,计算后再作为一个属性输出.

SQL代码:

SELECT Student.*,     (SELECT AVG(Grade)
                       FROM SC
                       WHERE SC.Sno = Student.Sno) AS 平均成绩
FROM Student
WHERE Sno IN (
                SELECT Sno
	        FROM  SC 
                WHERE Grade < 60
	        GROUP BY Sno
                HAVING COUNT(Grade) >=2);

 

 

  • 类型五:多字段分组的使用

题目:按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩(同时要求输出学生姓名)

分析:

第一步:肯定是拿SC表和Student表按学号进行连接

第二步:考虑分组,那么按学号分组的话,是无法输出姓名的,所以考虑多字段分组,按(Student.Sno ,Sname)进行分组,这样就可以输出姓名了

SQL代码:

SELECT Student.Sno ,Sname,AVG(Grade) AS 平均成绩
FROM SC,Student
WHERE SC.Sno = Student.Sno
GROUP BY Student.Sno ,Sname
ORDER BY 平均成绩 DESC;

 

 

  • 类型六:ORDER BY的使用  (DESC是降序,ASC是升序)

注:在PostgreSQL中降序的关键字是ASC,在其他关系型数据库中可能是AESC

题目:检索" 01 "课程分数小于 60,按分数降序排列的学生信息

SQL代码:

SELECT Student.*,Grade
FROM SC,Student
WHERE Student.Sno = SC.Sno AND  SC.Cno = '01' AND SC.Grade < 60
ORDER BY SC.Grade DESC;

​​​​​​​

 

  • 类型七.EXISTS查询

  题目:查询没学过"张三"老师讲授的任一门课程的学生姓名

分析:

第一步: 如果一个学生 x满足  " 没学过"张三"老师讲授的任一门课程的学生姓名​​​ ",那么可以等价转化为什么条件呢?

第二步:等价条件: 对于学生x,  他选修的所有课程, 肯定"不存在一门课程属于张三老师讲授的课程"

分析完后,我们就可以快速地写出来了

SQL代码:

SELECT Sname    
FROM Student x   
WHERE NOT EXISTS
      (
        SELECT*
        FROM SC y
        WHERE  y.Sno = x.Sno AND  EXISTS
              (
                  SELECT*
                  FROM Teacher,Course
                  WHERE Teacher.Tno = Course.Tno AND y.Cno = Course.Cno  AND Teacher.Tname ='张三' ));

​​​​​​​

 

  • 类型八.EXISTS查询易错类型

题目: 查询和" 01 "号的同学学习的课程 完全相同的其他同学的信息

分析:这道题有"完全"的字眼,一眼看上去,就想用EXISTS查询解决,但是后面查询结果是错的, 感觉用EXISTS查询做还是挺容易出错的

(嘻嘻,也可能是我太菜了~~)

第一步:我们先思考: 如果有个同学 x,学习的课程和"01"号同学完全相同,那么这个同学符合什么条件呢?

第二步::概括上述的条件:对于x,他选修的所有课程,  肯定"不存在一门课程是不在01同学的课程内的"

概括出了第二步的条件,我很自然地写出了下面错误的SQL:

SELECT x.*
FROM Student x
WHERE x.Sno != '01' AND NOT EXISTS
                (
                     SELECT*
                     FROM SC y
                     WHERE y.Sno = x.Sno AND NOT EXISTS
                          (
                              SELECT*
                              FROM SC z
                              WHERE z.Sno ='01' AND z.Cno = y.Cno));

为什么会错了,,我画个图就明白了:

如何以正确地姿势AK SQL查询50题(精华篇)_第3张图片

 

大家懂了吧!!上面的SQL代码查询出来的同学, 他们选修课程是01同学选修课程的子集,如图所示,a同学和b同学也会被筛选出来,但是他们明显不符合我们的结果  ......题目要求的是完全相同, 也就是要求等集,那么我们该怎么改进呢?

把第二步条件改为:  对于x,他选修的所有课程,  肯定"不存在一门课程是不在01同学的课程内的  && x选修的课程数等于01所选修的课程数"

正确SQL代码(非EXISTS查询):

分析:

第一步:拿两张SC表, 分别为x,y. 然后按照 x.Sno !='01' AND y.Sno = '01' AND x.Cno = y.Cno进行连接.  找出选修(01选修的课程) 

的记录, 由于这边还要输出学生的姓名,所以我们拿张Student表继续连接,以便输出姓名等信息

第二步:对第一步得到的表按照( Student.Sname,Student.Sno )进行分组, 然后用聚集函数判断该学生选修的(01选修的课程) 数是否和01同学相同

SQL代码:

SELECT Student.Sname,Student.Sno
FROM  SC x,SC y,Student
WHERE Student.Sno =x.Sno AND x.Sno !='01' AND y.Sno = '01' AND x.Cno = y.Cno 
GROUP BY Student.Sname,Student.Sno
HAVING COUNT(y.Cno) =(
                        SELECT COUNT(*)
                        FROM SC
                        WHERE  SC.Sno ='01'); 

 

 

 

  • 类型九.按某种属性排名,要求重复时 保留名次空缺

 什么是保留名次空缺:

姓名   成绩   排名
小A     99     1
小B     99     1
小C     98     3


/*
这里小C的98分虽然是第2高分,但是它是年级第三名.因为第一名并列2个,因此第2的名次就空缺了
像这种排列方法,就称为保留名次空缺.

每个人的名次 = 比我考得高分的人的数量 + 1
*/

​​​​​​​题目:按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺

分析:

第一步: 拿两张SC表,一张为x, 一张为y, 然后按照x.Cno = y.Cno AND y.Grade > x.Grade进行连接,目的是派生出一张表:

该表可以显示看对于某学生的某个科目,有多少人考得比它高. 当然了,还要按照( x.Sno,x.Cno,x.Grade)进行分组,

COUNT( y.Grade) + 1就是名次了 (没有加DISTINCE是默认不会去重的),该表称为xx

 

第二步:拿Student表和xx表进行连接,以便输出姓名等信息

SQL代码:

​
SELECT Student.*,xx.Cno,xx.Grade,xx.名次
FROM (
      SELECT x.Sno,x.Cno,x.Grade, COUNT(y.Grade) + 1 AS 名次
      FROM SC AS x LEFT OUTER JOIN SC AS y ON (x.Cno = y.Cno AND y.Grade > x.Grade)
      GROUP BY x.Sno,x.Cno,x.Grade
     ) AS xx,Student
WHERE Student.Sno = xx.Sno
ORDER BY xx.Cno, xx.名次;

​

 

如何以正确地姿势AK SQL查询50题(精华篇)_第4张图片

 

 

  • 类型10.按某种属性排名,要求重复时 不保留名次空缺

什么是不保留名次空缺:

姓名   成绩   排名
小A     99     1
小B     99     1
小C     98     2


/*
这里小C的98分是第2高分,,因此第2的名次就没有空缺了
像这种排列方法,就称为不保留名次空缺.

每个人的名次 = (>=我的分数类型有几种 )
*/

 

题目:按各科成绩进行排序,并显示排名, Score 重复时合并名次(不保留名次空缺)

分析:

第一步: 拿两张SC表,一张为x, 一张为y, 然后按照x.Cno = y.Cno AND y.Grade > x.Grade进行连接,目的是派生出一张表:

该表可以显示看对于出某学生的某个科目,有多少人考得比它高. 当然了,还要按照( x.Sno,x.Cno,x.Grade)进行分组, COUNT(DISTINCT y.Grade) 就是 >=我的分数类型的种类数,也就是名次,  把这张表命名为xx

第二步:拿Student表和xx表进行连接,以便输出姓名等信息

SQL代码:

 

SELECT xx.*,xx.Cno, xx.名次
FROM ( SELECT x.Sno,x.Cno, COUNT(DISTINCT y.Grade) AS 名次
        FROM SC AS x LEFT OUTER JOIN SC AS y ON (x.Cno = y.Cno AND y.Grade >= x.Grade)
        GROUP BY x.Sno,x.Cno
       ) AS xx,Student
WHERE Student.Sno = xx.Sno
ORDER BY xx.Cno, xx.名次;

如何以正确地姿势AK SQL查询50题(精华篇)_第5张图片

 

 

 

 

  • 类型11:输出优秀率或者及格率的题目


题目:以如下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90 (且要求输出课程号和选修人数,查询结果按选修人数降序排列,若人数相同,按课程号升序排列)  括号部分是我把另外一题合并进来的,更综合

分析:

第一步:首先生成4张派生表:a,b,c,d.   a表用来统计各科优秀的人数    b表用来统计各科优良的人数  c表用来统计各科中等的人数

d表用来统计各科及格的人数

/*d表*/
SELECT Course.Cno, COUNT(Grade) AS 及格人数
FROM Course LEFT OUTER JOIN SC ON (Course.Cno = SC.Cno AND SC.Grade >=60)
GROUP BY Course.Cno;

/*c表*/
SELECT Course.Cno, COUNT(Grade) AS 中等人数
FROM Course LEFT OUTER JOIN SC ON (Course.Cno = SC.Cno AND Grade >=70 AND Grade <80)
GROUP BY Course.Cno;
      
/*b表*/
SELECT Course.Cno, COUNT(Grade) AS 优良人数
FROM Course LEFT OUTER JOIN SC ON (Course.Cno = SC.Cno AND Grade >=80 AND Grade <90)
GROUP BY Course.Cno ;

/*a表*/
SELECT Course.Cno, COUNT(Grade) AS 优秀人数
FROM Course LEFT OUTER JOIN SC ON (Course.Cno = SC.Cno AND Grade >=90)
GROUP BY Course.Cno ;

第二步:生成派生表x,该表记录了各科的最高分,最低分,平均分,选修总人数

/*派生表*/

SELECT Course.Cno ,MAX(Grade) AS 最高分 ,COUNT(*) AS 选修人数, MIN(Grade) AS 最低分 ,AVG(Grade) AS 平均分
FROM Course LEFT OUTER JOIN SC ON (Course.Cno = SC.Cno )
GROUP BY Course.Cno;

第三步. a,b,c,d,x这5张表进行连接,并且对结果进行排序

SQL代码:

SELECT x.Cno AS 课程ID ,Course.Cname AS 课程name,  x.选修人数,x.最高分,x.最低分 ,x.平均分 ,d.及格人数*1.0/x.选修人数 AS 及格率 ,c.中等人数*1.0/x.选修人数 AS  中等率,
        b.优良人数*1.0/x.选修人数 AS 优良率, a.优秀人数*1.0/x.选修人数 AS 优秀率          
FROM 

     (SELECT Course.Cno, COUNT(Grade) AS 及格人数
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=60)
      GROUP BY Course.Cno ) AS d ,
     
 
     (SELECT Course.Cno, COUNT(Grade) AS 中等人数
      FROM  Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade>=70 AND Grade <80)
      GROUP BY Course.Cno ) AS c ,
      

     (SELECT Course.Cno, COUNT(Grade) AS 优良人数
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=80 AND Grade <90)
      GROUP BY Course.Cno ) AS b,

     (SELECT Course.Cno, COUNT(Grade) AS 优秀人数
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=90)
      GROUP BY Course.Cno ) AS a ,
  
     (SELECT Course.Cno ,MAX(Grade) AS 最高分 ,COUNT(*) AS 选修人数, MIN(Grade) AS 最低分 ,AVG(Grade) AS 平均分
      FROM  Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno )
      GROUP BY Course.Cno) AS x ,Course

WHERE d.Cno = c.Cno AND c.Cno = b.Cno AND b.Cno = a.Cno AND a.Cno = x.Cno AND x.Cno = Course.Cno
ORDER BY 选修人数 DESC, 课程ID ASC;

 

 

  • 类型十二: 查询各科前几名的记录

题目:查询各科成绩前三名的记录

分析:  这种查排名的题目,第一反应是要不要保留名次空缺,这题没有提到,说明题目不严谨

保留名次空缺:核心思想跟类型9一样

第一步:拿出两张SC表,分别为x,y表, 用x表去左外连接y表, 这边要用外连接,! 不然第一名的人由于没有人分数比他高, 无法被筛选,

连接后, 对于某个人的某个科目,都能直接看出有多少人比他高

第二步:对第一步的表按(Student.Sname,Student.Sno,x.Cno)进行分组. 再用HAVING语句筛选 COUNT(y.Grade) < 3的分组

SQL代码:

SELECT Student.Sname,Student.Sno,x.Cno,COUNT(y.Grade) + 1 AS 名次
FROM SC AS x LEFT OUTER JOIN SC AS y ON  (x.Cno = y.Cno AND y.Grade > x.Grade),Student
WHERE x.Sno = Student.Sno
GROUP BY Student.Sname,Student.Sno,x.Cno
HAVING COUNT(y.Grade) < 3
ORDER BY x.Cno DESC, 名次 ASC;

 

 不保留名次空缺:核心思想跟类型10一样

分析: 主要是一些条件变化了,直接看SQL代码比较差异,差异的原因请看类型10

SQL代码:

SELECT Student.Sname,Student.Sno,x.Cno,COUNT(DISTINCT y.Grade) AS 名次
FROM SC AS x LEFT OUTER JOIN SC AS y ON  (x.Cno = y.Cno AND y.Grade > x.Grade),Student
WHERE x.Cno = y.Cno AND y.Grade >= x.Grade AND Student.Sno = x.Sno
GROUP BY Student.Sname,Student.Sno,x.Cno
HAVING COUNT(DISTINCT y.Grade) <= 3
ORDER BY x.Cno DESC, 名次 ASC;

 

 

  • 类型13.  WHERE,GROUP BY ,HAVING ,ORDER BY的混合使用

题目:查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩,结果按平均成绩进行降序排列

分析:

第一步:执行WHERE语句,把Student和SC表进行连接,形成一张表,暂且称为x

第二步:按照( Student.Sno,Sname)对x表进行分组

第三步:执行HAVING语句,对每个分组进行筛选,筛选出AVG(SC.Grade) >=60的分组, 形成一张表,暂且称为y表

第四步:执行SELECT语句,筛选出字段,称为z表

第五步:执行ORDER BY语句, 对z表进行排序,按照成绩进行降序排序,称为结果表

SQL代码:

SELECT Student.Sno,Sname,AVG(SC.Grade) AS 平均成绩
FROM Student,SC
WHERE Student.Sno = SC.Sno
GROUP BY Student.Sno,Sname
HAVING AVG(SC.Grade) >=60
ORDER BY 平均成绩 DESC;


 

 

  • 类型14.查询任意成绩都大于某个值的信息

题目:查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数

分析:

第一步:拿出一张SC表 ,筛选出成绩>=70的选课记录

第二步:对第一步的表按x.Sno进行分组, 再用聚集函数筛选出 (>=70分的课程数) = (该学生选修的课程数)的分组.  称为xx表

第三步:用xx表和Student,SC表进行连接,以便输出姓名,课程名称

SQL代码:

SELECT Student.Sname, xx.Sno,Course.Cname,z.Grade
FROM	(
         SELECT x.Sno
	 FROM   SC x
	 WHERE  x.Grade >=70
	 GROUP BY x.Sno
	 HAVING COUNT(x.Grade) = (
                           	SELECT COUNT(*)
                           	FROM SC y
                           	WHERE y.Sno = x.Sno )
         ) AS xx, Course,Student,SC z
WHERE xx.Sno = Student.Sno AND z.Sno = xx.Sno AND Course.Cno = z.Cno;

 

 

  • 类型15.查询选修某老师所授课程的学生中,成绩最高的学生信息及其成绩

题目:成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩

题目:成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩

分析:这道题,由于是只求最高分,  我的解法适用于成绩有重复和不重复的两种情况.

第一步:拿Course, Teacher,SC表进行连接,

第二步:由于1个老师可能教授多门课程,且有可能叫"张三"的老师又多个, 所以我们要按照(Teacher.Tno,SC.Cno)进行分组,并且筛选

 出对应的字段,  其中一个字段就是某个课程的最高分 ,称为x表

第三步,再拿出一张SC表 ,Student表, 和x表进行连接 ,连接条件是:SC.Grade = x.MaxGrade AND SC.Cno = x.Cno AND Student.sno = SC.Sno,形成结果表

SQL代码:

SELECT  Student.*,SC.Cno,SC.Grade
FROM    (
          SELECT Teacher.Tno,  SC.Cno,MAX(SC.Grade) AS MaxGrade
          FROM  Course ,Teacher,SC
	  WHERE Course.Tno = Teacher.Tno AND Course.Cno = SC.Cno  AND Teacher.Tname ='张三'
          GROUP BY Teacher.Tno,SC.Cno
         )AS x, SC,Student

WHERE SC.Grade = x.MaxGrade AND SC.Cno = x.Cno AND Student.sno = SC.Sno;

​​​​​​​

 

  • 类型16.日期类型

分析:不同的关系型数据库,日期类型和对应的函数都不 尽相同, 可以去官方查询对应的文档,这边忽略了

 

五.SQL代码大全(不包括日期的题目)

//1.查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数

SELECT Student.*,x.Grade AS 课程1,y.Grade AS 课程2
FROM SC x,SC y,Student
WHERE Student.Sno = x.Sno AND x.Sno = y.Sno AND x.Cno ='01' AND y.Cno ='02' AND x.Grade > y.Grade;


//2.查询同时存在" 01 "课程和" 02 "课程的情况
SELECT DISTINCT x.Sno
FROM  SC x, SC y
WHERE x.Sno = y.Sno AND x.Cno ='01' AND y.Cno ='02';


//3.查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null )
SELECT x.*,y.Cno,y.Grade
FROM   (SELECT *
         FROM SC x
         WHERE Cno ='01'
         )  AS x

         LEFT OUTER JOIN 
         ( SELECT *
           FROM SC 
           WHERE Cno ='02'
         ) AS y ON (x.Sno = y.Sno);


 
//4.查询不存在" 01 "课程但存在" 02 "课程的情况
SELECT  x.Sno
FROM SC x
WHERE x.Cno ='02' AND x.Sno  NOT IN(

  SELECT DISTINCT y.Sno
   FROM SC yx
   WHERE y.Cno ='01'


);


//5.查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩,结果按平均成绩进行降序排列
SELECT Student.Sno,Sname,AVG(SC.Grade) AS 平均成绩
FROM Student,SC
WHERE Student.Sno = SC.Sno
GROUP BY Student.Sno,Sname
HAVING AVG(SC.Grade) >=60
ORDER BY 平均成绩 DESC;


//6.查询在 SC 表存在成绩的学生信息
SELECT Student.*
FROM Student
WHERE Student.Sno IN (

  SELECT SC.Sno
  FROM SC 
  GROUP BY SC.Sno
);



//7.查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
SELECT Student.Sno,Student.Sname,x.COUNT,x.SUM
FROM Student LEFT OUTER JOIN (
                              SELECT SC.Sno ,COUNT(SC.Cno),SUM(SC.Grade)
               		      FROM SC
              		      GROUP BY SC.Sno) AS x ON (Student.Sno = x.Sno);

// 8.查询「李」姓老师的数量
SELECT COUNT(*)
FROM Teacher
WHERE Tname Like '李%';


//9.查询学过「张三」老师授课的同学的信息
SELECT ALL Student.*
FROM Course,Teacher,SC,Student
WHERE SC.Cno = Course.Cno AND SC.Sno = Student.Sno AND Course.Tno = Teacher.Tno AND Teacher.Tname 
      ='张三';

                                          
//10.查询没有学全所有课程的同学的信息
SELECT *
FROM Student
WHERE EXISTS
      (
         SELECT*
         FROM Course
         WHERE NOT EXISTS
               (
                  SELECT*
                  FROM SC
                  WHERE SC.Sno= Student.Sno AND Course.Cno = SC.Cno ));


                     
//11.查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息
SELECT DISTINCT Sno
FROM SC x
WHERE  EXISTS
      (
          SELECT*
          FROM SC y
          WHERE y.Sno = x.Sno AND  EXISTS
                (
                   
                    SELECT *
                    FROM SC z
                    WHERE z.Sno ='01' AND z.Cno = y.Cno));

 
  
//12.查询和" 01 "号的同学学习的课程 完全相同的其他同学的信息

SELECT Student.Sname,Student.Sno
FROM  SC x,SC y,Student
WHERE Student.Sno =x.Sno AND x.Sno !='01' AND y.Sno = '01' AND x.Cno = y.Cno 
GROUP BY Student.Sname,Student.Sno
HAVING COUNT(y.Cno) =(
                        SELECT COUNT(*)
                        FROM SC
                        WHERE  SC.Sno ='01'); 


//13.查询没学过"张三"老师讲授的任一门课程的学生姓名
SELECT Sname    
FROM Student x   
WHERE NOT EXISTS
      (
        SELECT*
        FROM SC y
        WHERE  y.Sno = x.Sno AND  EXISTS
              (
                  SELECT*
                  FROM Teacher,Course
                  WHERE Teacher.Tno = Course.Tno AND y.Cno = Course.Cno  AND Teacher.Tname ='张三' ));




//14.查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
SELECT Student.*,     (SELECT AVG(Grade)
                       FROM SC
                       WHERE SC.Sno = Student.Sno) AS 平均成绩
FROM Student
WHERE Sno IN (
                SELECT Sno
	        FROM  SC 
                WHERE Grade < 60
	        GROUP BY Sno
                HAVING COUNT(Grade) >=2);
               
  


//15.检索" 01 "课程分数小于 60,按分数降序排列的学生信息
SELECT Student.*,Grade
FROM SC,Student
WHERE Student.Sno = SC.Sno AND  SC.Cno = '01' AND SC.Grade < 60
ORDER BY SC.Grade DESC;

//16.按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
SELECT Student.Sno ,Sname,AVG(Grade) AS 平均成绩
FROM SC,Student
WHERE SC.Sno = Student.Sno
GROUP BY Student.Sno ,Sname
ORDER BY 平均成绩 DESC;

//17.查询各科成绩最高分、最低分和平均分:
SELECT Cno,MAX(Grade) AS 最高分,MIN(Grade) AS 最低分,AVG(Grade) AS 平均分
FROM SC 
GROUP BY Cno;


//18.以如下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
要求输出课程号和选修人数,查询结果按选修人数降序排列,若人数相同,按课程号升序排列


SELECT x.Cno AS 课程ID ,Course.Cname AS 课程name,  x.选修人数,x.最高分,x.最低分 ,x.平均分 ,d.及格人数*1.0/x.选修人数 AS 及格率 ,c.中等人数*1.0/x.选修人数 AS  中等率,
        b.优良人数*1.0/x.选修人数 AS 优良率, a.优秀人数*1.0/x.选修人数 AS 优秀率          
FROM 

     (SELECT Course.Cno, COUNT(Grade) AS 及格人数
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=60)
      GROUP BY Course.Cno ) AS d ,
     
 
     (SELECT Course.Cno, COUNT(Grade) AS 中等人数
      FROM  Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade>=70 AND Grade <80)
      GROUP BY Course.Cno ) AS c ,
      

     (SELECT Course.Cno, COUNT(Grade) AS 优良人数
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=80 AND Grade <90)
      GROUP BY Course.Cno ) AS b,

     (SELECT Course.Cno, COUNT(Grade) AS 优秀人数
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=90)
      GROUP BY Course.Cno ) AS a ,
  
     (SELECT Course.Cno ,MAX(Grade) AS 最高分 ,COUNT(*) AS 选修人数, MIN(Grade) AS 最低分 ,AVG(Grade) AS 平均分
      FROM  Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno )
      GROUP BY Course.Cno) AS x ,Course

WHERE d.Cno = c.Cno AND c.Cno = b.Cno AND b.Cno = a.Cno AND a.Cno = x.Cno AND x.Cno = Course.Cno
ORDER BY 选修人数 DESC, 课程ID ASC;



//19.按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺
SELECT Student.*,xx.Cno,xx.Grade,xx.名次
FROM (
      SELECT x.Sno,x.Cno,x.Grade, COUNT(y.Grade) + 1 AS 名次
      FROM SC AS x LEFT OUTER JOIN SC AS y ON (x.Cno = y.Cno AND y.Grade > x.Grade)
      GROUP BY x.Sno,x.Cno,x.Grade
     ) AS xx,Student
WHERE Student.Sno = xx.Sno
ORDER BY xx.Cno, xx.名次;


//20.按各科成绩进行排序,并显示排名, Score 重复时合并名次
SELECT xx.*,xx.Cno, xx.名次
FROM ( SELECT x.Sno,x.Cno, COUNT(DISTINCT y.Grade) AS 名次
        FROM SC AS x LEFT OUTER JOIN SC AS y ON (x.Cno = y.Cno AND y.Grade >= x.Grade)
        GROUP BY x.Sno,x.Cno
       ) AS xx,Student
WHERE Student.Sno = xx.Sno
ORDER BY xx.Cno, xx.名次;

  
//21.查询学生的总成绩,并进行排名,总分重复时保留名次空缺   
SELECT  x.Sno,x.总分,COUNT( y.总分) + 1 AS 名次
FROM
        ( SELECT Sno,SUM(Grade) AS 总分
          FROM  SC 
	  GROUP BY Sno
         ) AS x 
         
         LEFT OUTER JOIN 

	( SELECT Sno,SUM(Grade) AS 总分
          FROM SC
	  GROUP BY Sno
        ) AS y  ON(y.总分 > x.总分)      

GROUP BY x.Sno,x.总分
ORDER BY x.总分 DESC;

//22.查询学生的总成绩,并进行排名,总分重复时不保留名次空缺
SELECT  x.Sno,Sname,x.总分,COUNT(DISTINCT y.总分) AS 名次
FROM
        ( SELECT Student.Sno,Sname,SUM(Grade) AS 总分
          FROM  Student LEFT OUTER JOIN SC ON(Student.Sno = SC.Sno )
	  GROUP BY Student.Sno,Sname
         ) AS x 
         
         LEFT OUTER JOIN 

	( SELECT Sno,SUM(Grade) AS 总分
          FROM SC
	  GROUP BY Sno
        ) AS y  ON(y.总分 >= x.总分)      

GROUP BY x.Sno,x.Sname,x.总分
ORDER BY x.总分 DESC;


//23.统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比

SELECT x.Cno AS 课程编号,x.Cname AS 课程名称,d.D*1.0/x.总人数 AS D比例, c.C*1.0/x.总人数 AS C比例,b.B*1.0/x.总人数 AS B比例, a.A*1.0/x.总人数 AS A比例
FROM 
     ( SELECT Course.Cno ,COUNT(SC.Grade) AS D
       FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno AND SC.Grade >=0 AND SC.Grade <60)
       GROUP BY Course.Cno
     ) AS d,
     ( SELECT  Course.Cno ,COUNT(SC.Grade) AS C
       FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno AND SC.Grade >=60 AND SC.Grade <70)覆盖 
       GROUP BY Course.Cno
     ) AS c,
     ( SELECT  Course.Cno ,COUNT(SC.Grade) AS B
       FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno AND SC.Grade >=70 AND SC.Grade<85)
       GROUP BY Course.Cno
     ) AS b,
     ( SELECT  Course.Cno ,COUNT(SC.Grade) AS A
       FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno AND SC.Grade >=85 AND SC.Grade < 100)
       GROUP BY Course.Cno
     ) AS a,
     ( SELECT Course.Cno ,Course.Cname,COUNT(SC.Grade) AS 总人数
       FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno)
       GROUP BY Course.Cno,Course.Cname
     ) AS x
WHERE a.Cno = b.Cno AND b.Cno = c.Cno AND c.Cno = d.Cno AND d.Cno = x.Cno;



//24.查询每门课程被选修的学生数
SELECT Course.Cno,Course.Cname,COUNT(SC.Sno) AS 学生数
FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno)
GROUP BY Course.Cno,Course.Cname;

       
//25 .查询各科成绩前三名的记录
保留名次空缺:
SELECT Student.Sname,Student.Sno,x.Cno,COUNT(y.Grade) + 1 AS 名次
FROM SC AS x LEFT OUTER JOIN SC AS y ON  (x.Cno = y.Cno AND y.Grade > x.Grade),Student
WHERE x.Sno = Student.Sno
GROUP BY Student.Sname,Student.Sno,x.Cno
HAVING COUNT(y.Grade) < 3
ORDER BY x.Cno DESC, 名次 ASC;


//不保留名次空缺
SELECT Student.Sname,Student.Sno,x.Cno,COUNT(DISTINCT y.Grade) AS 名次
FROM SC AS x LEFT OUTER JOIN SC AS y ON  (x.Cno = y.Cno AND y.Grade > x.Grade),Student
WHERE x.Cno = y.Cno AND y.Grade >= x.Grade AND Student.Sno = x.Sno
GROUP BY Student.Sname,Student.Sno,x.Cno
HAVING COUNT(DISTINCT y.Grade) <= 3
ORDER BY x.Cno DESC, 名次 ASC;



//26.查询出只选修两门课程的学生学号和姓名
SELECT Student.Sno,Sname
FROM Student LEFT OUTER JOIN SC ON (SC.Sno = Student.Sno) 
GROUP BY Student.Sno,Sname
HAVING COUNT(SC.Cno) =2;

//27.查询男生、女生人数
SELECT Ssex,COUNT(*) AS 人数
FROM Student
GROUP BY Ssex;

//28.查询名字中含有「风」字的学生信息
SELECT *
FROM Student
WHERE Sname LIKE '%风%';


//29.查询同名同性学生名单,并统计同名人数
SELECT x.Sname, COUNT(y.Sname) AS 人数
FROM Student x,Student y
WHERE x.Sname =y.Sname AND x.Ssex = y.Ssex AND x.Sno !=y.Sno
GROUP BY x.Sname;

//30.查询 1990 年出生的学生名单
SELECT Student.*
FROM Student
WHERE extract(year from Sage) = 1990;

//31.查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
SELECT Cno,AVG(Grade) AS 平均成绩
FROM SC
GROUP BY Cno
ORDER BY 平均成绩 DESC, Cno ASC; 

//32.查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
SELECT x.Sno,Student.Sname,AVG(y.Grade) AS 平均成绩
FROM SC x, SC y,Student
WHERE x.Sno = y.Sno AND Student.Sno = y.Sno
GROUP BY x.Sno,Student.Sname
HAVING AVG(y.Grade) >= 85;

//33.查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
SELECT Student.Sname,SC.Grade
FROM Student, SC,Course
WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno AND Course.Cname ='数学'AND SC.Grade <60;

//34.查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
SELECT Student.*,SC.Cno ,Course.Cname ,SC.Grade
FROM Student LEFT OUTER JOIN SC ON (Student.Sno = SC.Sno)  LEFT OUTER JOIN Course ON (Course.Cno = SC.Cno);


//35.查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
SELECT Student.Sname, xx.Sno,Course.Cname,z.Grade
FROM	(
         SELECT x.Sno
	 FROM   SC x
	 WHERE  x.Grade >=70
	 GROUP BY x.Sno
	 HAVING COUNT(x.Grade) = (
                           	SELECT COUNT(*)
                           	FROM SC y
                           	WHERE y.Sno = x.Sno )
         ) AS xx, Course,Student,SC z
WHERE xx.Sno = Student.Sno AND z.Sno = xx.Sno AND Course.Cno = z.Cno;


//36.查询不及格的课程
SELECT  Student.*,SC.Cno,Course.Cname,SC.Grade
FROM SC,Student,Course
WHERE SC.Sno = Student.Sno AND SC.Cno = Course.Cno AND SC.Grade < 60;

//37.查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
SELECT Student.Sno ,Student.Sname,SC.Cno,Course.Cname,SC.Grade
FROM SC ,Student,Course
WHERE SC.Sno = Student.Sno AND SC.Cno = Course.Cno AND SC.Cno = '01' AND SC.Grade >=80;



//38.求每门课程的学生人数
SELECT Course.Cno,Course.Cname,COUNT(*) AS 选修人数
FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno)
GROUP BY Course.Cno,Course.Cname;

//39.成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
SELECT  Student.*,SC.Cno,SC.Grade
FROM    (
          SELECT Teacher.Tno,  SC.Cno,MAX(SC.Grade) AS MaxGrade
          FROM  Course ,Teacher,SC
	  WHERE Course.Tno = Teacher.Tno AND Course.Cno = SC.Cno  AND Teacher.Tname ='张三'
          GROUP BY Teacher.Tno,SC.Cno
         )AS x, SC,Student

WHERE SC.Grade = x.MaxGrade AND SC.Cno = x.Cno AND Student.sno = SC.Sno;

          

//40.成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
SELECT  Student.*,x.SC.Cno,SC.Grade
FROM    (
          SELECT Teacher.Tno,  SC.Cno,MAX(SC.Grade) AS MaxGrade
          FROM  Course ,Teacher,SC
	  WHERE Course.Tno = Teacher.Tno AND Course.Cno = SC.Cno  AND Teacher.Tname ='张三'
          GROUP BY Teacher.Tno,SC.Cno
         )AS x, SC,Student

WHERE SC.Grade = x.MaxGrade AND SC.Cno = x.Cno AND Student.sno = SC.Sno;


//41.查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
SELECT x.Sno, x.Cno As Cno1 ,y.Cno As Con2,x.Grade AS 相同成绩
FROM SC x ,SC y
WHERE x.Grade = y.Grade AND x.Sno = y.Sno AND x.Cno != y.Cno;


//42.查询每门功成绩最好的前两名
       SELECT x.Sno,x.Cno,x.Grade ,COUNT(y.Grade) AS Cnt
       FROM SC AS x LEFT OUTER JOIN SC AS y ON (x.Cno = y.Cno AND y.Grade >x.Grade)
       GROUP BY x.Sno,x.Cno,x.Grade
       HAVING COUNT(y.Grade)  < 2;

//43.查询选修了全部课程的学生信息
SELECT *
FROM Student x
WHERE NOT EXISTS
      (
          SELECT*
          FROM Course y
          WHERE  NOT EXISTS
             (
                SELECT*
                FROM SC z
                WHERE z.Sno = x.Sno AND z.Cno = y.Cno ));

 

 

 

 

 

你可能感兴趣的:(数据库)