型如下面这样的就是嵌套查询:

SELECT Sname
FROM Student
WHERE Sno IN(
	SELECT Sno
	FROM SC
	WHERE Cno = '2'
);

SELECT语句不能使用ORDER BY子句
ORDER BY只能对最终查询结果排序

带有IN谓词的子查询

IN谓词用于子查询结果是一个集合的情况

例3.55:查询与“刘晨”在同一个系学习的学生

先分步用单表查询做
第一步:

SELECT Sdept
FROM Student
WHERE Sname='刘晨';

在这里插入图片描述

SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept='CS'; /*CS位置添加 上面查询到的系名*/

在这里插入图片描述
所以根据这个原理,我们可以进行一下嵌套查询,将代码合并一下:

SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN(
	SELECT Sdept
	FROM Student
	WHERE Sname='刘晨'--;	
);

在嵌套查询中,IN谓词后面的语句块中,结尾不需要添加分号
并且字符串都是用单引号来引用的,双引号会报错(可能习惯了C语言的问题,这里总是不习惯)
在这里插入图片描述

除此之外,这道例题也可以使用自身连接来查询

SELECT Sno,Sname,Sdept
FROM Student S1,Student S2
WHERE S1.Sdept = S2.Sdept AND S1.Sname = '刘晨'; 

在这里插入图片描述

这里给我报错是因为虽然是自身连接,但是还是要指明要选取的是哪个表格的组

SELECT S1.Sno,S1.Sname,S1.Sdept
FROM Student S1,Student S2
WHERE S1.Sdept = S2.Sdept AND S2.Sname = '刘晨'; 

在这里插入图片描述

例3.56:查询选修了课程名为“信息系统”的学生学号和姓名

SELECT Sno,Sname
FROM Student
WHERE Sno IN(
	SELECT Sno
	FROM SC
	WHERE Cno IN(
		SELECT Cno
		FROM Course
		WHERE Cname = '信息系统'
	)
);

在这里插入图片描述

这道题我感觉上课听的时候感觉好抽象,现在看看其实也不是理解的很透彻

嵌套查询首先要注意的是,从内向外

  1. 先在Course表中找到信息系统的课程号
  2. 再根据课程号,在SC表中找选修了信息课程的学生学号
  3. 最后根据第二步查到的学生学号,在Student表中找到学生的学号和姓名


    嵌套查询有一个特点:就是 WHERE 的条件查询的属性,一定是在内层中要SELECT选择的属性

这道题也可以使用连接查询实现

SELECT Student,Sno,student.Sname
FROM Student,Course,SC
WHERE Student.Sno = Course.Sno AND
		Course.Cno = SC.Cno

带有比较运算符的子查询

常见的比较运算符是>,<,=,>=,<=,!=,<>等。
例3.55中的IN就可以用 = 来实现

SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN(
	SELECT Sdept
	FROM Student
	WHERE Sname='刘晨'--;	
);

例3.57:找出每个学生超过他自己选修课程平均成绩的课程号

SELECT Sno,Cno
FROM SC x
WHERE Grade >= (
	SELECT AVG(Grade)
	FROM SC y
	WHERE y.Sno = x.Sno
);

(相关子查询)查询步骤是:

  1. 从外层查询中选出一个SC的元组的x,将元组x的Sno的值在传到内层查询
  2. 执行内层循环,将得到的值代替内层查询
  3. 执行外层查询

带有ANY(SOME)或ALL谓词的子查询

>ANY	大于子查询结果中的某个值
>ALL	大于子查询结果中的所有值
<ANY	小于子查询结果中的某个值
<ALL	小于子查询结果中的所有值
>=ANY	大于等于子查询结果中的某个值
>=ALL	大于等于子查询结果中的所有值
<=ANY	小于等于子查询结果中的某个值
<=ALL	小于等于子查询结果中的所有值
=ANY	等于子查询结果中的某个值
=ALL	等于子查询结果中的所有值(通常没有实际意义)
!=(或<>) ANY	不等于子查询结果中的某个值
!=(或<>) ANY	不等于子查询结果中的所有值

例3.58:查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄

SELECT Sname,Sage
FROM Student
WHERE Sdept != 'CS' AND Sage < ANY(
	SELECT Sage
	FROM Student
	WHERE Sdept = 'CS'
);

在这里插入图片描述
本题目可以使用聚集函数来实现(先查询出CS系中最大年龄20,再查询出非CS系中年龄小于20岁的学生)

SELECT Sname,Sage
FROM Student
WHERE Sdept != 'CS' AND Sage < (
	SELECT MAX(Sage)
	FROM Student
	WHERE Sdept = 'CS'
);

小于ANY就是小于任何一个值,说明小于哪一个都可以,所以小于MAX就好(上课时候没理解ANY的含义,想的是小于所有值,没整明白,哈哈,英语不太好)

例3.59:查询非计算机科学系中比计算机科学系所有学生年龄小的学生姓名和年龄

SELECT Sname,Sage
FROM Student
WHERE Sdept != 'CS' AND Sage < ALL(
	SELECT Sage
	FROM Student
	WHERE Sdept = 'CS'
);

在这里插入图片描述

我个人觉得不像书上那么写,将所有约束条件写在一起,将有嵌套的查询写在最后,这样更加好理解

SELECT Sname,Sage
FROM Student
WHERE Sdept != 'CS' AND Sage <(
	SELECT Min(Sage)
	FROM Student
	WHERE Sdept = 'CS'
);

事实上,聚集函数实现子查询 通常 比直接用ANY和ALL效率高

带有EXISTS谓词的子查询

EXISTS代表存在量词,带有EXISTS的子查询不返回任何数据,只产生true和false两个值

例3.60:查询所有选修了1号课程的学生姓名

SELECT Sname
FROM Student
WHERE EXISTS(
	SELECT *
	FROM SC
	WHERE Sno = Student.sno AND Cno = '1'
);

在这里插入图片描述

由EXISTS引出的子查询,其目标列表达式通常用 * 表示,因为我们只需要知道他在不在表中即可

例3.61:查询没有选修1号课程的学生姓名

SELECT Sname
FROM Student
WHERE NOT EXISTS(
	SELECT *
	FROM SC
	WHERE Sno = Student.sno AND Cno = '1'
);

在这里插入图片描述

一些带有EXISTS 或 NOT EXISTS谓词的子查询不能被其他形式的子查询等价交换,但所有带IN谓词、比较运算符、ANY、ALL谓词的子查询都能带EXISTS谓词的子查询等价交换

SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN(
	SELECT Sdept
	FROM Student
	WHERE Sname='刘晨'--;	
);

上面这个3.55的例子就可以替换成以下

SELECT Sno,Sname,Sdept
FROM Student S1
WHERE EXISTS(
	SELECT *
	FROM Student S2
	WHERE S2.Sdept = S1.Sdept AND S2.Sname = '刘晨'
);

例3.62:查询选修了全部课程的学生姓名

SQL中不存在全程量词
所以对于任意量词我们可以根据离散数学的知识改写一下
用存在来表示任意

SELECT Sname
FROM Student
WHERE NOT EXISTS(
	SELECT *
	FROM Course
	WHERE NOT EXISTS(
		SELECT *
		FROM SC
		WHERE Sno = Student.Sno AND Cno = Course.Cno
	)
);

选取全部课程的学生 就是 没有课程(Course)不是他没选的(SC)

例3.63:查询至少选修了学生201215122选秀的全部课程的学生号码

SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS(
	SELECT *
	FROM SC SCY
	WHERE SCY.Sno = '201215122' AND NOT EXISTS(
		SELECT * 
		FROM SC SCZ
		WHERE SCZ.Sno = SCX.Sno AND SCZ.Cno = SCY.Cno
	)
);

在这里插入图片描述

感觉带有 EXISTS 谓词地方的题目,复杂起来非常难于理解透彻,尽管我已经写好了一遍,但还是感觉很晦涩,这两天我再自己琢磨一下,等我完全领悟了,再把这个地方自己的理解补上来

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐