这是一个很好的问题,所以我决定在我的博客上写一篇有关此主题的非常详细的文章。
数据库表模型
假设我们的数据库中有以下两个表,它们构成一对多的表关系。
该student
表是父student_grade
表,它是子表,因为它有一个Student_id外键列,该列引用了学生表中的id主键列。
将student table
包含以下两个记录:
| id | first_name | last_name | admission_score |
|----|------------|-----------|-----------------|
| 1 | Alice | Smith | 8.95 |
| 2 | Bob | Johnson | 8.75 |
并且,该student_grade
表存储学生获得的成绩:
| id | class_name | grade | student_id |
|----|------------|-------|------------|
| 1 | Math | 10 | 1 |
| 2 | Math | 9.5 | 1 |
| 3 | Math | 9.75 | 1 |
| 4 | Science | 9.5 | 1 |
| 5 | Science | 9 | 1 |
| 6 | Science | 9.25 | 1 |
| 7 | Math | 8.5 | 2 |
| 8 | Math | 9.5 | 2 |
| 9 | Math | 9 | 2 |
| 10 | Science | 10 | 2 |
| 11 | Science | 9.4 | 2 |
SQL存在
假设我们想让所有在数学课上获得10年级的学生。
如果我们仅对学生标识符感兴趣,则可以运行如下查询:
SELECT
student_grade.student_id
FROM
student_grade
WHERE
student_grade.grade = 10 AND
student_grade.class_name = 'Math'
ORDER BY
student_grade.student_id
但是,该应用程序有兴趣显示a的全名 student
,而不仅仅是标识符,因此我们也需要student
表中的信息。
为了过滤student
数学成绩为10 的记录,我们可以使用EXISTS SQL运算符,如下所示:
SELECT
id, first_name, last_name
FROM
student
WHERE EXISTS (
SELECT 1
FROM
student_grade
WHERE
student_grade.student_id = student.id AND
student_grade.grade = 10 AND
student_grade.class_name = 'Math'
)
ORDER BY id
运行上面的查询时,我们可以看到仅选择了Alice行:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
外部查询选择 student
我们有兴趣返回给客户端行列。但是,WHERE子句将EXISTS运算符与关联的内部子查询一起使用。
如果子查询返回至少一条记录,则EXISTS运算符返回true;如果未选择任何行,则返回false。数据库引擎不必完全运行子查询。如果单个记录匹配,则EXISTS运算符返回true,并选择关联的其他查询行。
内部子查询是相关的,因为student_grade
表的student_id列与外部学生表的id列匹配。
SQL不存在
让我们考虑一下,我们要选择所有年级不低于9的学生。为此,我们可以使用NOT EXISTS,这会否定EXISTS运算符的逻辑。
因此,如果基础子查询不返回任何记录,则NOT EXISTS运算符将返回true。但是,如果内部子查询匹配单个记录,则NOT EXISTS运算符将返回false,并且可以停止执行子查询。
要匹配没有关联的Student_grade且其值小于9的所有学生记录,我们可以运行以下SQL查询:
SELECT
id, first_name, last_name
FROM
student
WHERE NOT EXISTS (
SELECT 1
FROM
student_grade
WHERE
student_grade.student_id = student.id AND
student_grade.grade < 9
)
ORDER BY id
运行上面的查询时,我们可以看到只有Alice记录被匹配:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
因此,使用SQL EXISTS和NOT EXISTS运算符的好处是,只要找到匹配的记录,就可以停止内部子查询的执行。