美文网首页
SQL:exists 和 not exists 介绍

SQL:exists 和 not exists 介绍

作者: 蓝笔头 | 来源:发表于2021-06-18 16:53 被阅读0次

语法

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)

提示:数据通过后面的建表语句和初始化语句创建。

  • tPostgreSQL 中表示 true
  • fPostgreSQL 中表示 false

上面的 existsnot exists 语句

初始化测试环境

以 PostgreSQL 为例

  1. 建表语句
CREATE TABLE live_lesson_question (
    id bigserial NOT NULL PRIMARY KEY,
    live_lesson_id bigint NOT NULL,
    start_date date not NULL
);
  1. 初始化数据
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 实战

  1. 查询每个 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_datestart_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)
  1. 查询每个 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_datestart_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 实战

  1. 查询每个 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 的记录,t1start_date 最大的记录不满足这个条件,因此会被排除。

  1. 查询每个 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 的记录,t1start_date 最小的记录不满足这个条件,因此会被排除。

总结

  • exists : 有结果集返回,则为 ture,或者为 false
  • not exists : 有结果集返回,则为 false,或者为 true

exists 子句不在乎返回什么,而是在乎是不是有结果集返回。
一个常用的编码习惯是用 exists(SELECT 1 WHERE ...) 的形式写所有的 exists 测试。

参考

相关文章

网友评论

      本文标题:SQL:exists 和 not exists 介绍

      本文链接:https://www.haomeiwen.com/subject/zyxlyltx.html