语法
EXISTS (subquery)
NOT EXISTS (subquery)
EXISTS
的参数是一个任意的 SELECT
语句, 或者说子查询。
系统对子查询进行运算以判断它是否返回行。
- 如果它至少返回一行,那么
EXISTS
的结果就为true
; 如果子查询没有返回行,那么EXISTS
的结果是false
。
这个子查询通常只是运行到能判断它是否可以返回至少一行为止, 而不是等到全部结束。
因为结果只取决于是否会返回行,而不取决于这些行的内容, 所以这个子查询的输出列表通常是无关紧要的。
一个常用的编码习惯是用 EXISTS(SELECT 1 WHERE ...)
的形式写所有的 EXISTS
测试。
演示
> select * from live_lesson_question where id=1;
id | live_lesson_id | start_date
----+----------------+------------
1 | 102 | 2020-04-07
> select exists (select * from live_lesson_question where id=1);
exists
--------
t
> select not exists (select * from live_lesson_question where id=1);
?column?
----------
f
(1 row)
提示:数据通过后面的建表语句和初始化语句创建。
-
t
在PostgreSQL
中表示true
。 -
f
在PostgreSQL
中表示false
。
上面的 exists
和 not exists
语句
初始化测试环境
以 PostgreSQL 为例
- 建表语句
CREATE TABLE live_lesson_question (
id bigserial NOT NULL PRIMARY KEY,
live_lesson_id bigint NOT NULL,
start_date date not NULL
);
- 初始化数据
INSERT INTO live_lesson_question (live_lesson_id, start_date)
values
(102, '2020-04-07'),
(102, '2020-04-08'),
(102, '2020-04-09'),
(102, '2020-04-10'), -- 102 中 start_date 最大
(203, '2020-04-10'),
(203, '2020-04-09'),
(203, '2020-04-11'), -- 203 中 start_date 最大
(203, '2020-04-05'),
(304, '2020-04-05'),
(304, '2020-04-15'), -- 304 中 start_date 最大
(304, '2020-04-12'),
(304, '2020-04-06');
not exists 实战
- 查询
每个 live_lesson_id 分组
中start_date
最大的记录。
select * from live_lesson_question t1 where
not exists (select 1 from live_lesson_question t2 where t1.live_lesson_id = t2.live_lesson_id and t2.start_date > t1.start_date);
没有记录的 start_date
比 start_date 最大
的记录还要大。
所以可以转化为查询同一个 live_lesson_id 分组(t1.live_lesson_id = t2.live_lesson_id
)中,不存在 t2.start_date > t1.start_date
的记录。
输出符合预期:
id | live_lesson_id | start_date
----+----------------+------------
4 | 102 | 2020-04-10
7 | 203 | 2020-04-11
10 | 304 | 2020-04-15
(3 rows)
- 查询
每个 live_lesson_id 分组
中start_date
最小的记录。
select * from live_lesson_question t1 where
not exists (select 1 from live_lesson_question t2 where t1.live_lesson_id = t2.live_lesson_id and t2.start_date < t1.start_date);
没有记录的 start_date
比 start_date 最小
的记录还要小。
所以可以转化为查询同一个 live_lesson_id 分组(t1.live_lesson_id = t2.live_lesson_id
)中,不存在 t2.start_date < t1.start_date
的记录。
输出符合预期:
id | live_lesson_id | start_date
----+----------------+------------
1 | 102 | 2020-04-07
8 | 203 | 2020-04-05
9 | 304 | 2020-04-05
(3 rows)
exists 实战
- 查询每个
live_lesson_id 分组
中除最大的start_date
的所有记录。
select * from live_lesson_question t1 where
exists (select 1 from live_lesson_question t2 where t1.live_lesson_id = t2.live_lesson_id and t2.start_date > t1.start_date);
在原表 t2
中存在比 t1
中条件为 t2.start_date > t1.start_date
的记录,t1
中 start_date
最大的记录不满足这个条件,因此会被排除。
- 查询每个
live_lesson_id 分组
中除最小的start_date
的所有记录。
select * from live_lesson_question t1 where
exists (select 1 from live_lesson_question t2 where t1.live_lesson_id = t2.live_lesson_id and t2.start_date < t1.start_date);
在原表 t2
中存在比 t1
中条件为 t2.start_date < t1.start_date
的记录,t1
中 start_date
最小的记录不满足这个条件,因此会被排除。
总结
-
exists
: 有结果集返回,则为ture
,或者为false
。 -
not exists
: 有结果集返回,则为false
,或者为true
。
exists
子句不在乎返回什么,而是在乎是不是有结果集返回。
一个常用的编码习惯是用 exists(SELECT 1 WHERE ...)
的形式写所有的 exists
测试。
网友评论