谓词是一种特殊的函数,返回值是真值。谓词逻辑提供谓词是为了判断命题的真假。
参数是行数据的集合。
在EXISTS的子查询里,SELECT子句的列表可以有下面这三种写法。
- 通配符:SELECT *
- 常量:SELECT ‘这里的内容任意’
- 列名:SELECT col
在SQL中,为了表达全称量化,需要将“所有的行都满足条件P”这样的命题转换成“不存在不满足条件P的行”。
查询表中“不”存在的数据
在有些情况下,不得不从表中查找出“不存在的数据”。例如下面这样的情况。
求“没有参加某次会议的人”,该怎么做呢?目标结果如下所示,是各次会议缺席者的列表。
思路是先假设所有人都参加了全部会议,并以此生成一个集合,然后从中减去实际参加会议的人,这样就能得到缺席会议的人。
1 | -- 存在量化 |
还可以用集合论的方法,像下面这样使用差集运算。
1 | -- 差集运算 |
通过以上两条SQL语句的比较可以明白,NOT EXISTS直接具备了差集运算的功能。
全称量化(1):习惯“肯定<->双重否定”之间的转换
这里使用下面这样一张存储了学生考试成绩的表为例。
先来看一个简单的问题:请查询出“所有科目分数都在50分以上的学生”。
1 | SELECT DISTINCT student_id |
接下来把条件改得复杂一些。思考一下如何查询出满足下列条件的学生。
- 数学的分数在80分以上。
- 语文的分数在50分以上。
结果应该是学号分别为100、200、400的学生。
1 | SELECT DISTINCT student_id |
接下来,思考一下如何排除掉没有语文分数的学号为400的学生。
1 | SELECT student_id |
全称量化(2):集合VS谓词——哪个更强大?
EXISTS和HAVING有一个地方很像,即都是以集合而不是个体为单位操作数据。实际上,两者在很多情况下都是可以互换的。接下来通过比较来了解一下它们各自的优点和缺点。
假设存在下面这样的项目工程管理表。
这里的问题是,从这张表中查询出哪些项目已经完成到了工程1。
1 | -- 面向集合 |
用谓词逻辑该如何解决呢?
1 | -- 谓词逻辑 |
与HAVING相比,使用了NOT EXISTS代码看起来不是那么容易理解,这是它的缺点。但是这种写法也有优点。第一个优点是性能好。只要有一行满足条件,查询就会终止,不一定需要查询所有行的数据。而且还能通过连接条件使用“project_id”列的索引,这样查询起来会更快。第二个优点是结果里包含的信息量更大。如果使用HAVING,结果会被聚合,只能获取到项目ID,而如果使用EXISTS,则能把集合里的元素整体都获取到。
对列进行量化:查询全是1的行
这张表的设计不好的原因是,数组中的元素可以自由地增加或者减少,而表中的列却不能这样。因此在设计表时有一条原则:让列具有一定的扩展性。数组中的元素不应该对应表中的列,而是应该对应行。
在使用这种模拟数组的表时遇到的需求一般都是下面这两种形式。
- 查询“都是1”的行
- 查询“至少有一个9”的行
对于这个问题,需要进行“列方向”的量化。
1 | SELECT * |
反过来,如果想表达“至少有一个9”这样的存在量化命题,可以使用ALL的反义谓词ANY。
1 | SELECT * |
或者也可以使用IN谓词代替ANY。
1 | SELECT * |
但是,如果左边不是具体值而是NULL,这种写法就不行了。这种情况下,需要使用COALESCE函数。
1 | SELECT * |











