#查询输出“高等数学”课程成绩前三名(不考虑成绩有重复值的情况)的学生的学号,姓名,课程名,系名(sdept),成绩。
select s.sno,s.sname,s.sdept,sc.grade,c.cname from student s
join sc on s.sno=sc.sno join course c on sc.cno=c.cno
where c.cname="高等数学"
order by sc.grade desc
limit 3;
# 或者:两种都是多表连接的表示方式
select s.sno,s.sname,s.sdept,sc.grade,c.cname from student s,course c,sc
where s.sno=sc.sno and sc.cno=c.cno
and c.cname="高等数学"
order by sc.grade desc
limit 3;
#统计各门课程的重修人数(包括grade为NULL),要求输出课程代号,课程名及重修人数。
select c.cno,c.cname,count(*) from course c,sc
where c.cno = sc.cno and (grade<60 or grade is null)
group by c.cno;
讲一下为什么需要group by
操作
在这个SQL查询中,group by
语句的作用是将结果按照指定的列进行分组,然后对每个分组进行聚合计算。在这个问题中,我们需要统计每门课程的重修人数,这就需要将选修了同一门课程的学生分成一组,然后计算这个组内选修该课程的人数。
在SQL中,group by
语句用于指定分组的列,count(*)
函数用于统计每个分组的行数,也就是该门课程的重修人数。因此,在这个查询中,group by
语句的作用就是将选修了同一门课程的学生分组,然后对每个分组计算该门课程的重修人数。
如果不使用group by
语句,那么查询的结果将会是所有选修了该门课程的学生的总人数,而不是每门课程的重修人数。因此,group by
语句是必须的,它可以将结果按照课程分组,然后对每个分组计算该门课程的重修人数,从而得到正确的结果。
学生数据库db_student包括三个数据表student(学生表)、course(课程表)和sc(选课表)。表结构如下:
1、student(学生表):
SNO学号CHAR(7)
SNAME姓名CHAR(10)
SSEX性别CHAR(2)
SAGE年龄SMALLINT
SDEPT所在系 VARCHAR(20)
2、course(课程表)
CNO课程号CHAR(10)
CNAME课程名VARCHAR(20)
CCREDIT学分SMALLINT
SEMSTER学期SMALLINT
PERIOD学时SMALLINT
3、sc(选课表)
SNO 学号CHAR(7)
CNO 课程号CHAR(10)
GRADE 成绩 SMALLINT
#查询输出平均成绩在2-5名的学生,输出学号、姓名和平均成绩(取整),平均成绩降序。【不用考虑空值】
select s.sno,s.sname,round(avg(sc.grade)) from student s,sc
where sc.sno = s.sno
group by sc.sno
order by round(avg(grade)) DESC
limit 1,4;
本题讲解一下limit
的用法:
限制返回的行数。可以有两个参数,第一个参数为起始行,从 0 开始;第二个参数为返回的总行数。
因此输出2-5名的写法也显而易见了。
有课程表,学生表,成绩表如下,查询超过该课程平均分的成绩信息,输出学号,课程号及成绩。
course
列名 | 数据类型 | 约束 | 说明 |
cno | char(4) | 主键非空 | 课程号 |
cname | varchar(40) | 非空 | 课程名 |
cpno | char(4) | 参照course(cno) | 先修课 |
ccredit | tinyint | 学分 |
student
列名 | 数据类型 | 约束 | 说明 |
sno | char(7) | 主键非空 | 学号 |
sname | char(10) | 非空 | 学生姓名 |
ssex | enum(‘男’,‘女’) | 默认‘男’ | 性别 |
sage | tinyint | 年龄 | |
sdept | char(20) | 默认’计算机系’ | 系别 |
sc
列名 | 数据类型 | 约束 | 说明 |
sno | char(7) | 主键非空,参照student(sno) | 学号 |
cno | char(4) | 主键非空,参照course(cno) | 课程号 |
grade | decimal(5,1) | 成绩 | |
ccredit | tinyint |
# 查询超过该课程平均分的成绩信息
select a.sno,a.cno,a.grade from sc a
where a.grade>(select avg(sc.grade) from sc where sc.cno=a.cno);
sc
表中选取所有记录,并给它们起了一个别名 a
。where
子句中,我们使用了一个子查询:select avg(sc.grade) from sc where sc.cno=a.cno
。这个子查询的作用是计算每个课程的平均分数,其中 a.cno
表示当前记录所属的课程号。因此,子查询的结果就是当前记录所属课程的平均分数。a.grade
来筛选出所有分数高于该门课程平均分的学生成绩信息,即 a.grade > (select avg(sc.grade) from sc where sc.cno=a.cno)
。select a.sno, a.cno, a.grade from sc a
。#查询选修平均分为60分(包括60分)以上的学生的各门课成绩,要求输出学号,姓名,课程名和成绩,并按学号升序排序。
select s.sno,s.sname,c.cname,a.grade
from student s, course c, sc a
where s.sno=a.sno
and c.cno=a.cno
and s.sno in (select sno from sc group by sno having avg(grade)>=60)
order by s.sno;
子查询的作用:s.sno in (select sno from sc group by sno having avg(grade)>=60)
具体来说,这个子查询分为三个部分:
SELECT sno FROM sc
:从 sc
表中选择学生学号(sno
)。GROUP BY sno
:按学号进行分组。HAVING AVG(grade) >= 60
:筛选出平均成绩大于等于60分的学生。在这里,AVG(grade)
计算分组后的平均成绩,HAVING
子句用于筛选满足条件的分组,即平均成绩大于等于60分的学生。然后,这个子查询会返回一个学生学号的列表,这个列表中包含平均成绩大于等于60分的学生。接着,主查询中使用 s.sno IN
将这个列表与 student
表连接起来,从而筛选出相应的学生信息。换句话说,主查询中只会返回在子查询返回的学生学号列表中的学生信息。
学生数据库db_student包括三个数据表student(学生表)、course(课程表)和sc(选课表)。表结构如下:
1、student(学生表):
SNO学号CHAR(7)
SNAME姓名CHAR(10)
SSEX性别CHAR(2)
SAGE年龄SMALLINT
SDEPT所在系 VARCHAR(20)
2、course(课程表)
CNO课程号CHAR(10)
CNAME课程名VARCHAR(20)
CCREDIT学分SMALLINT
SEMSTER学期SMALLINT
PERIOD学时SMALLINT
3、sc(选课表)
SNO 学号CHAR(7)
CNO 课程号CHAR(10)
GRADE 成绩 SMALLINT
select * from student s
where s.sname !='王大力' and s.sdept = (select sdept from student where sname = '王大力');
# 本题需要注意先判断不是王大力本人再做子查询
有课程表,学生表,成绩表如下,请完成查询。
course
列名 | 数据类型 | 约束 | 说明 |
cno | char(4) | 主键非空 | 课程号 |
cname | varchar(40) | 非空 | 课程名 |
cpno | char(4) | 参照course(cno) | 先修课 |
ccredit | tinyint | 学分 |
student
列名 | 数据类型 | 约束 | 说明 |
sno | char(7) | 主键非空 | 学号 |
sname | char(10) | 非空 | 学生姓名 |
ssex | enum(‘男’,‘女’) | 默认‘男’ | 性别 |
sage | tinyint | 年龄 | |
sdept | char(20) | 默认’计算机系’ | 系别 |
sc
列名 | 数据类型 | 约束 | 说明 |
sno | char(7) | 主键非空,参照student(sno) | 学号 |
cno | char(4) | 主键非空,参照course(cno) | 课程号 |
grade | decimal(5,1) | 成绩 | |
ccredit | tinyint |
# 查询每门课的先修课,输出课程号、课程名和先修课程名。
select a.cno,a.cname,b.cname
from course a,course b
where a.cpno=b.cno;
SELECT
子句中,我们选择输出三个字段:课程号 (cno
)、课程名 (cname
) 和先修课程名 (b.cname
),因此使用了 SELECT a.cno, a.cname, b.cname
。FROM
子句中,我们选择了两次 course
表,分别表示当前课程和先修课程。WHERE
子句中,我们使用了条件 a.cpno = b.cno
来连接当前课程和先修课程。具体来说,a.cpno
表示当前课程的先修课程号,b.cno
表示先修课程的课程号。通过这个条件,我们可以找到每门课程的先修课程。有课程表,学生表,成绩表如下,请完成查询。
course
列名 | 数据类型 | 约束 | 说明 |
cno | char(4) | 主键非空 | 课程号 |
cname | varchar(40) | 非空 | 课程名 |
cpno | char(4) | 参照course(cno) | 先修课 |
ccredit | tinyint | 学分 |
student
列名 | 数据类型 | 约束 | 说明 |
sno | char(7) | 主键非空 | 学号 |
sname | char(10) | 非空 | 学生姓名 |
ssex | enum(‘男’,‘女’) | 默认‘男’ | 性别 |
sage | tinyint | 年龄 | |
sdept | char(20) | 默认’计算机系’ | 系别 |
sc
列名 | 数据类型 | 约束 | 说明 |
sno | char(7) | 主键非空,参照student(sno) | 学号 |
cno | char(4) | 主键非空,参照course(cno) | 课程号 |
grade | decimal(5,1) | 成绩 | |
ccredit | tinyint |
select s.sno,sname,grade
from student s,sc,course c
where s.sno = sc.sno and c.cno = sc.cno
and (grade is not null) and cname='高等数学';
有课程表,学生表,成绩表如下,请完成查询,查询学生成绩单,要求输出有有效成绩的学号,姓名,课程名,成绩,按学号升序课程名降序排列。
course
列名 | 数据类型 | 约束 | 说明 |
cno | char(4) | 主键非空 | 课程号 |
cname | varchar(40) | 非空 | 课程名 |
cpno | char(4) | 参照course(cno) | 先修课 |
ccredit | tinyint | 学分 |
student
列名 | 数据类型 | 约束 | 说明 |
sno | char(7) | 主键非空 | 学号 |
sname | char(10) | 非空 | 学生姓名 |
ssex | enum(‘男’,‘女’) | 默认‘男’ | 性别 |
sage | tinyint | 年龄 | |
sdept | char(20) | 默认’计算机系’ | 系别 |
sc
列名 | 数据类型 | 约束 | 说明 |
sno | char(7) | 主键非空,参照student(sno) | 学号 |
cno | char(4) | 主键非空,参照course(cno) | 课程号 |
grade | decimal(5,1) | 成绩 | |
ccredit | tinyint |
# 查询学生成绩单,要求输出有有效成绩的学号,姓名,课程名,成绩,按学号升序课程名降序排列。
select student.sno,sname,cname,grade
from student,sc,course
where grade is not null and student.sno=sc.sno and course.cno=sc.cno
order by sno asc,cname desc;
表结构如下:
select s.sno,s.sname,avg(sc.grade),count(*) from student s,sc,course c
where c.cno = sc.cno and s.sno = sc.sno
group by s.sno
order by avg(sc.grade) desc;
学生数据库db_student包括三个数据表student(学生表)、course(课程表)和sc(选课表)。表结构如下:
1、student(学生表):
SNO学号CHAR(7)
SNAME姓名CHAR(10)
SSEX性别CHAR(2)
SAGE年龄SMALLINT
SDEPT所在系 VARCHAR(20)
2、course(课程表)
CNO课程号CHAR(10)
CNAME课程名VARCHAR(20)
CCREDIT学分SMALLINT
SEMSTER学期SMALLINT
PERIOD学时SMALLINT
3、sc(选课表)
SNO 学号CHAR(7)
CNO 课程号CHAR(10)
GRADE 成绩 SMALLINT
# 查询选修通过2门(包括2门)以上的学生的信息,输出学号、选修通过门数、平均成绩,按门数降序排序,若门数相同,按照成绩降序。
select sno,count(*),round(avg(grade)) from sc
where grade>=60
group by sno
having count(*)>=2
order by 2 desc,3 desc;
学生数据库db_student包括三个数据表student(学生表)、course(课程表)和sc(选课表)。表结构如下:
1、student(学生表):
SNO学号CHAR(7)
SNAME姓名CHAR(10)
SSEX性别CHAR(2)
SAGE年龄SMALLINT
SDEPT所在系 VARCHAR(20)
2、course(课程表)
CNO课程号CHAR(10)
CNAME课程名VARCHAR(20)
CCREDIT学分SMALLINT
SEMSTER学期SMALLINT
PERIOD学时SMALLINT
3、sc(选课表)
SNO 学号CHAR(7)
CNO 课程号CHAR(10)
GRADE 成绩 SMALLINT
select cno,count(*) from sc where grade<=60 or grade is null
group by cno order by cno;
学生数据库db_student包括三个数据表student(学生表)、course(课程表)和sc(选课表)。表结构如下:
1、student(学生表):
SNO学号CHAR(7)
SNAME姓名CHAR(10)
SSEX性别CHAR(2)
SAGE年龄SMALLINT
SDEPT所在系 VARCHAR(20)
2、course(课程表)
CNO课程号CHAR(10)
CNAME课程名VARCHAR(20)
CCREDIT学分SMALLINT
SEMSTER学期SMALLINT
PERIOD学时SMALLINT
3、sc(选课表)
SNO 学号CHAR(7)
CNO 课程号CHAR(10)
GRADE 绩 SMALLINT
#查询统计学生不及格(低于60分)门数大于等于2门的信息,输出系名,学号,姓名,不及格门数,按照系(升序)排序,不及格门数(降序)排序。
select s.sdept,s.sno,s.sname,count(*) from student s ,sc
where s.sno=sc.sno
and sc.grade<60
group by s.sno
having count(*)>=2
order by s.sdept,count(*) desc;
学生数据库db_student包括三个数据表student(学生表)、course(课程表)和sc(选课表)。表结构如下:
1、student(学生表):
SNO学号CHAR(7)
SNAME姓名CHAR(10)
SSEX性别CHAR(2)
SAGE年龄SMALLINT
SDEPT所在系 VARCHAR(20)
2、course(课程表)
CNO课程号CHAR(10)
CNAME课程名VARCHAR(20)
CCREDIT学分SMALLINT
SEMSTER学期SMALLINT
PERIOD学时SMALLINT
3、sc(选课表)
SNO 学号CHAR(7)
CNO 课程号CHAR(10)
GRADE 成绩 SMALLINT
# 查询选修了“计算机网络”或者“数据库基础”课程的学生的学号,姓名
SELECT s.sno, s.sname
FROM student s
JOIN sc ON s.sno = sc.sno
JOIN course c ON sc.cno = c.cno
WHERE c.cname IN ('计算机网络', '数据库基础')
GROUP BY s.sno
ORDER BY s.sno ASC;
#查询选修了全部课程的学生的学号,姓名,系名
[注意:SQL表名请用小写]
学生数据库db_student包括三个数据表student(学生表)、course(课程表)和sc(选课表)。表结构如下:
1、student(学生表):
SNO学号CHAR(7)
SNAME姓名CHAR(10)
SSEX性别CHAR(2)
SAGE年龄SMALLINT
SDEPT所在系 VARCHAR(20)
2、course(课程表)
CNO课程号CHAR(10)
CNAME课程名VARCHAR(20)
CCREDIT学分SMALLINT
SEMSTER学期SMALLINT
PERIOD学时SMALLINT
3、sc(选课表)
SNO 学号CHAR(7)
CNO 课程号CHAR(10)
GRADE 成绩 SMALLINT
#查询选修了全部课程的学生的学号,姓名,系名
SELECT s.SNO, s.SNAME, s.SDEPT
FROM student s
WHERE NOT EXISTS (
SELECT c.CNO
FROM course c
WHERE NOT EXISTS (
SELECT *
FROM sc
WHERE sc.SNO = s.SNO AND sc.CNO = c.CNO
)
)
这个SQL查询语句可以分为两部分:外部查询和内部查询。
外部查询:
SELECT s.SNO, s.SNAME, s.SDEPT
FROM student s
WHERE NOT EXISTS (
...
)
在外部查询中,我们从学生表student中选择学号(SNO)、姓名(SNAME)和系名(SDEPT)。接下来,我们使用NOT EXISTS子句来筛选掉那些没有选修全部课程的学生。NOT EXISTS子句的作用是,对于学生表中的每一行,检查内部查询是否返回了任何匹配的课程。如果内部查询没有返回任何匹配的课程,那么NOT EXISTS子句返回TRUE,这意味着该学生选修了所有课程。反之,如果内部查询返回了任何匹配的课程,那么NOT EXISTS子句返回FALSE,这意味着该学生没有选修全部课程。
内部查询:
SELECT c.CNO
FROM course c
WHERE NOT EXISTS (
SELECT *
FROM sc
WHERE sc.SNO = s.SNO AND sc.CNO = c.CNO
)
在内部查询中,我们从课程表course中选择课程号(CNO)。接下来,我们使用NOT EXISTS子句来查找没有选修过这门课程的学生。NOT EXISTS子句的作用是,对于课程表中的每一行,检查子查询是否返回了任何匹配的选课记录。如果子查询没有返回任何匹配的选课记录,那么NOT EXISTS子句返回TRUE,这意味着没有学生选修这门课程。反之,如果子查询返回了任何匹配的选课记录,那么NOT EXISTS子句返回FALSE,这意味着有学生选修了这门课程。
查询不姓张的学生的基本信息。学生(student)表结构如下:
select * from student where sname not like '张%'
学生数据库db_student包括三个数据表student(学生表)、course(课程表)和sc(选课表)。表结构如下:
1、student(学生表):
SNO学号CHAR(7)
SNAME姓名CHAR(10)
SSEX性别CHAR(2)
SAGE年龄SMALLINT
SDEPT所在系 VARCHAR(20)
2、course(课程表)
CNO课程号CHAR(10)
CNAME课程名VARCHAR(20)
CCREDIT学分SMALLINT
SEMSTER学期SMALLINT
PERIOD学时SMALLINT
3、sc(选课表)
SNO 学号CHAR(7)
CNO 课程号CHAR(10)
GRADE 成绩 SMALLINT
#查询每个学生高于他自己选修平均分的那门课程的成绩,输出学号,课程号,课程成绩,他所有课程的平均分(取整),并按学号升序排列。
select sc.sno,cno, grade,avggrade
from sc,(select sno,round(avg(grade)) as avggrade from sc group by sno) as avg_sc
where sc.sno = avg_sc.sno and sc.grade>avg_sc.avggrade
order by sc.sno;
具体来说,这个查询语句中的派生表部分如下:
(SELECT sno, ROUND(AVG(grade)) AS avggrade FROM sc GROUP BY sno) AS avg_sc
在这个派生表中,我们使用GROUP BY子句按照学生号(sno)分组,并计算每个学生的平均成绩(AVG(grade)),并使用ROUND函数将平均成绩四舍五入为整数。最终,我们将学生号(sno)和平均成绩(avggrade)作为结果集返回,并将其命名为avg_sc。然后,在外部查询中,我们使用WHERE子句将选课表sc和派生表avg_sc联接起来,并筛选出成绩高于平均成绩的选课记录。