前言------
AK: ALL Killed
这学期学数据库系统概论,作为一个初学者,必须先熟练掌握SQL的基本查询语句,在完成了老师的SQL50题之后,我把我自己地AK姿势记录下来, 便于回忆之余,也希望对大家有帮助.
"博客要精心雕琢,我是米开朗基罗", 雕琢了两天,然后没保存好,实在是太憋屈了,,,不甘心,现在终于补回来了,可以好好睡了.
自认为是SQL50题查询中最完善的博客,写文章不容易啊,终于知道计算机的书籍为啥都这么贵了....
目录
一.完成这50题之前首先做什么?
二.这50题要怎么做
三.建表并且插入数据
四.给人以鱼,不如授之以渔: 题目精选解析
五.SQL代码大全(不包括日期的题目)
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.把中文输入法的符号改为英文符号,这绝对能节省一大半的时间
上部分的语句和下部分的语句,差别就在箭头处的符号是中文字符.......这种错误有时很难查找,会让你一脸懵逼的,所以建议大家
禁止掉中文符号!!!!!!!! (以搜狗输入法为例)
我觉得这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 '%风%';
题目:查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
分析:
第一步:我们依次枚举每个学生,
第二步每当我们枚举一个学生,就应该判断该该学会是不是属于"两门及其以上不及格课程的"的学号集合中;
第三步:所以我们要去找出"两门及其以上不及格课程的"的学号集合"
第四步:确定了在上述集合中后,我们认定这个学生应该输出,但是要输出平均成绩怎么办呢?在输出平均成绩的时候,在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;
注:在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;
题目:查询没学过"张三"老师讲授的任一门课程的学生姓名
分析:
第一步: 如果一个学生 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 ='张三' ));
题目: 查询和" 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));
为什么会错了,,我画个图就明白了:
大家懂了吧!!上面的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.名次;
什么是不保留名次空缺:
姓名 成绩 排名
小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.名次;
题目:以如下形式显示:课程 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;
题目:查询平均成绩大于等于 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;
题目:查询任何一门课程成绩在 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;
题目:成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
题目:成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
分析:这道题,由于是只求最高分, 我的解法适用于成绩有重复和不重复的两种情况.
第一步:拿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;
分析:不同的关系型数据库,日期类型和对应的函数都不 尽相同, 可以去官方查询对应的文档,这边忽略了
//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 ));