子查询
使用子查询,可以用一系列简单的查询构成复杂的查询,从而增强SQL语句的功能。
在SQL语言中,一个SELECT-FROM-WHERE语句称为一个查询块。在WHERE子句或HAVING子句所指定条件中,可以使用另一个查询块的查询的结果作为条件的一部分,这种将一个查询块嵌套在另一个查询块的子句指定条件中的查询称为嵌套查询。
例如:
SELECT *
FROM student
WHERE sno IN
(SELECT sno
FROM score
WHERE cno='1004'
);
在本例中,下层查询块“SELECT stno FROM score WHERE cno=‘203’”的查询结果,作为上层查询块“SELECT * FROM student WHERE stno IN”的查询条件,上层查询块称为父查询或外层查询,下层查询块称为子查询(Subquery)或内层查询,嵌套查询的处理过程是由内向外,即由子查询到父查询,子查询的结果作为父查询的查询条件。
PL/SQL允许SELECT多层嵌套使用,即一个子查询可以嵌套其它子查询,以增强查询能力。
子查询通常与IN、EXIST谓词和比较运算符结合使用。
IN子查询
在IN子查询中,使用IN谓词实现子查询和父查询的连接。
语法格式:
<表达式> [ NOT ] IN ( <子查询>)
说明:
在IN子查询中,首先执行括号内的子查询,再执行父查询,子查询的结果作为父查询的查询条件。
当表达式与子查询的结果集中的某个值相等时,IN谓词返回TRUE,否则返回FALSE;若使用了NOT,则返回的值相反。
【例1】查询选修了课程号为8001的课程的学生情况。
SELECT *
FROM student
WHERE sno IN
(SELECT sno
FROM score
WHERE cno='8001'
);
【例2】查询未选修数字电路课程的学生情况。
SELECT
FROM student
WHERE sno NOT IN
(SELECT sno
FROM score
WHERE cno IN
(SELECT cno
FROM course
WHERE cname='数字电路'
)
);
先在课程表中得到课程名为‘数字电路’的课程号,然后再根据这个课程号在成绩表中找学号,然后选取不是这些学号的其他学生
【例3】查询选修某课程的学生人数多于4人的教师姓名。
SELECT tname AS 教师姓名
FROM teacher
WHERE tno IN
(SELECT a.tno
FROM course a, score b
WHERE a.cno=b.cno
GROUP BY a.tno //写成a.cno也可以,因为一个课程对应一个老师
HAVING COUNT(a.tno)>4 //写成a.cno也可以
);
首先要分组,得到课程(或者教师号),条件是选修的人数多于4人,然后再得到老师名字
也可以不用子查询,直接用三表连接
【例4】查询在计算机专业任课的教师情况。
SELECT *
FROM teacher
WHERE tno IN
(SELECT a.tno
FROM teacher a, course b, score c, student d
WHERE a.tno=b.tno AND b.cno=c.cno AND c.sno=d.sno AND d.speciality='计算机'
);
比较子查询
比较子查询是指父查询与子查询之间用比较运算符进行关联。
语法格式:
<表达式> { < | <= | = | > | >= | != | <> } { ALL | SOME | ANY } ( <子查询> )
说明:
关键字ALL、SOME和ANY用于对比较运算的限制,ALL指定表达式要与子查询结果集中每个值都进行比较,当表达式与子查询结果集中每个值都满足比较关系时,才返回TRUE,否则返回FALSE;SOME和ANY指定表达式要只与子查询结果集中某个值满足比较关系时,就返回TRUE,否则返回FALSE。
【例1】查询比所有计算机专业学生年龄都小的学生。
SELECT *
FROM student
WHERE sbirthday >ALL
(SELECT sbirthday
FROM student
WHERE speciality='计算机'
);
注意:年龄小的生日日期大
这里的方法是找生日日期大于所有计算机学生的生日日期的学生,也可以找先找计算机学生生日日期最大的(MAX),然后比他生日日期大的就比所有计算机学生的生日日期都大
【例2】查询课程号8001的成绩高于课程号4002成绩的学生。
SELECT *
FROM score
WHERE cno='8001' AND grade>= ANY
(SELECT grade
FROM score
WHERE cno='4002'
);
题目是高于,没有说要高于所有的,所以随表高于一个就行了
EXISTS子查询
在EXISTS子查询中,EXISTS谓词只用于测试子查询是否返回行,若子查询返回一个或多个行,则EXISTS返回TRUE,否则返回FALSE,如果为NOT EXISTS,其返回值与EXIST相反。
语法格式:
[ NOT ] EXISTS ( <子查询> )
说明:
在EXISTS子查询中,父查询的SELECT语句返回的每一行数据都要由子查询来评价,如果EXISTS谓词指定条件为TRUE,查询结果就包含该行,否则该行被丢弃。
【例1】查询选修1004课程的学生姓名。
SELECT sname AS 姓名
FROM student
WHERE EXISTS
(SELECT *
FROM score
WHERE score.sno=student.sno AND cno='1004'
);
内层的score可以与外层的student连接,但是在外层,不能与内层的表做连接
(子查询可以使用父查询的表,父查询不能使用子查询的表)
该语句的执行过程,例如,先外层,找到一个学生名字张三,然后到内层,张三并没有选修,子查询返回值是faulse,然后就不用进行下去了,改名字跳过,然后下一个,李四,他选修了,子查询返回ture,然后就保留
所以一定要有score.sno=student.sno
这一句,主表和内表要有连接
【例2】查询所有任课教师姓名和学院。
SELECT tname AS 教师姓名, school AS 学院
FROM teacher a
WHERE EXISTS
(SELECT *
FROM course b
WHERE a.tno=b.tno
);
综合练习
1)查询选修数据库系统课程的学生的姓名、性别、班级和成绩。
SELECT a.sname AS 姓名, a.ssex AS 性别, a.sclass AS 班级, b.cname AS 课程名, c.grade AS 成绩
FROM student a, course b, score c
WHERE a.sno=c.sno AND b.cno=c.cno AND b.cname='数据库系统';
2)查找选修了8001课程且为计算机专业学生的姓名及成绩,查出的成绩按降序排列。
SELECT a.sname AS 姓名, b.cname AS 课程名, c.grade AS 成绩
FROM student a, course b, score c
WHERE b.cno='8001' AND a.sno=c.sno AND b.cno=c.cno
ORDER BY grade DESC;
3)查询既选修了英语又选修了数据库系统的学生的学号、姓名、出生日期和专业;查询既选修了英语又未选修数据库系统的学生的学号、姓名、出生日期和专业。
①查询既选修了英语又选修了数据库系统的学生的学号、姓名、出生日期和专业
SELECT a.sno AS 学号, a.sname AS 姓名, a.sbirthday AS 出生日期, a.speciality AS 专业
FROM student a, course b, score c
WHERE a.sno=c.sno AND b.cno=c.cno AND b.cname='英语'
INTERSECT
SELECT a.sno AS 学号, a.sname AS 姓名, a.sbirthday AS 出生日期, a.speciality AS 专业
FROM student a, course b, score c
WHERE a.sno=c.sno AND b.cno=c.cno AND b.cname='数据库系统';
②查询既选修了英语又未选修数据库系统的学生的学号、姓名、出生日期和专业。
SELECT a.sno AS 学号, a.sname AS 姓名, a.sbirthday AS 出生日期, a.speciality AS 专业
FROM student a, course b, score c
WHERE a.sno=c.sno AND b.cno=c.cno AND b.cname='英语'
MINUS
SELECT a.sno AS 学号, a.sname AS 姓名, a.sbirthday AS 出生日期, a.speciality AS 专业
FROM student a, course b, score c
WHERE a.sno=c.sno AND b.cno=c.cno AND b.cname='数据库系统';
4)查找学号为124001,课程名为”高等数学”的学生成绩。
SELECT *
FROM score
WHERE sno='124001' and cno IN
(SELECT cno
FROM course
WHERE cname='高等数学'
);