SQL谓词简介
目录
- 一、什么是谓词
- 二、LIKE 谓词——字符串的部分一致查询
- 2.1 前方一致查询
- 2.2 中间一致查询
- 2.3 后方一致查询
- 三、BETWEEN 谓词——范围查询
- 四、IS NULL、IS NOT NULL——判断是否为 NULL
- 五、IN 谓词——OR 的简便用法
- 六、使用子查询作为 IN 谓词的参数
- 6.1 IN 和子查询
- 6.2 NOT IN 和子查询
- 七、EXISTS 谓词
- 7.1 EXISTS 谓词的使用方法
- 7.1.1 EXISTS 的参数
- 7.1.2 子查询中的 SELECT *
- 7.1.3 使用 NOT EXISTS 替换 NOT IN
- 7.1 EXISTS 谓词的使用方法
- 请参阅
学习重点
谓词就是返回值为真值的函数。
掌握
LIKE
的三种使用方法(前方一致、中间一致、后方一致)。需要注意
BETWEEN
包含三个参数。想要取得
NULL
数据时必须使用IS NULL
。可以将子查询作为
IN
和EXISTS
的参数。
一、什么是谓词
本文将会和大家一起学习 SQL 的抽出条件中不可或缺的工具——谓词(predicate)。虽然之前我们没有提及谓词这个概念,但其实大家已经使用过了。例如,=
、<
、>
、<>
等比较运算符,其正式的名称就是比较谓词。
KEYWORD
- 谓词
通俗来讲谓词就是 各种各样的函数 中介绍的函数中的一种,是需要满足特定条件的函数,该条件就是返回值是真值。对通常的函数来说,返回值有可能是数字、字符串或者日期等,但是谓词的返回值全都是真值(TRUE
/FALSE
/UNKNOWN
)。这也是谓词和函数的最大区别。
本文将会介绍以下谓词。
LIKE
BETWEEN
IS NULL、IS NOT NULL
IN
EXISTS
二、LIKE
谓词——字符串的部分一致查询
截至目前,我们使用字符串作为查询条件的例子中使用的都是 =
。这里的 =
只有在字符串完全一致时才为真。与之相反,LIKE
谓词更加模糊一些,当需要进行字符串的部分一致查询时需要使用该谓词。
KEYWORD
LIKE
谓词部分一致查询
部分一致大体可以分为前方一致、中间一致和后方一致三种类型。接下来就让我们来看一看具体示例吧。
首先我们来创建一张表 1 那样的只有 1 列的表。
表 6-1 SampleLike
表
strcol
(字符串)
abcddd
dddabc
abdddc
abcdd
ddabc
abddc
创建上表以及向其中插入数据的 SQL 语句请参考代码清单 21。
代码清单 21 创建 SampleLike
表
-- DDL :创建表CREATE TABLE SampleLike
( strcol VARCHAR(6) NOT NULL,
PRIMARY KEY (strcol));
SQL Server PostgreSQL
-- DML :插入数据BEGIN TRANSACTION; -------①
INSERT INTO SampleLike (strcol) VALUES ("abcddd");
INSERT INTO SampleLike (strcol) VALUES ("dddabc");
INSERT INTO SampleLike (strcol) VALUES ("abdddc");
INSERT INTO SampleLike (strcol) VALUES ("abcdd");
INSERT INTO SampleLike (strcol) VALUES ("ddabc");
INSERT INTO SampleLike (strcol) VALUES ("abddc");
COMMIT;
特定的 SQL
不同的 DBMS 事务处理的语法也不尽相同。代码清单 21 中的 DML 语句在 MySQL 中执行时,需要将 ① 部分更改为“
START TRANSACTION;
”,在 Oracle 和 DB2 中执行时,无需用到 ① 的部分(请删除)。详细内容请大家参考 事务 中的“创建事务”。
想要从该表中读取出包含字符串“ddd
”的记录时,可能会得到前方一致、中间一致和后方一致等不同的结果。
前方一致:选取出“
dddabc
”所谓前方一致,就是选取出作为查询条件的字符串(这里是“
ddd
”)与查询对象字符串起始部分相同的记录的查询方法。中间一致:选取出“
abcddd
”“dddabc
”“abdddc
”所谓中间一致,就是选取出查询对象字符串中含有作为查询条件的字符串(这里是“
ddd
”)的记录的查询方法。无论该字符串出现在对象字符串的最后还是中间都没有关系。后方一致:选取出“
abcddd
”后方一致与前方一致相反,也就是选取出作为查询条件的字符串(这里是“
ddd
”)与查询对象字符串的末尾部分相同的记录的查询方法。
KEYWORD
前方一致
中间一致
后方一致
从本例中我们可以看出,查询条件最宽松,也就是能够取得最多记录的是中间一致。这是因为它同时包含前方一致和后方一致的查询结果。
像这样不使用“=
”来指定条件字符串,而以字符串中是否包含该条件(本例中是“包含 ddd
”)的规则为基础的查询称为模式匹配,其中的模式也就是前面提到的“规则”。
KEYWORD
模式匹配
模式
2.1 前方一致查询
下面让我们来实际操作一下,对 SampleLike
表进行前方一致查询(代码清单 22)。
代码清单 22 使用 LIKE
进行前方一致查询
SELECT * FROM SampleLike
WHERE strcol LIKE "ddd%";
执行结果
strcol--------
dddabc
其中的 %
是代表“0 字符以上的任意字符串”的特殊符号,本例中代表“以 ddd
开头的所有字符串”。
KEYWORD
%
这样我们就可以使用 LIKE
和模式匹配来进行查询了。
2.2 中间一致查询
接下来让我们看一个中间一致查询的例子,查询出包含字符串“ddd
”的记录(代码清单 23)。
代码清单 23 使用 LIKE
进行中间一致查询
SELECT * FROM SampleLike
WHERE strcol LIKE "%ddd%";
执行结果
strcol--------
abcddd
dddabc
abdddc
在字符串的起始和结束位置加上 %
,就能取出“包含 ddd
的字符串”了。
2.3 后方一致查询
最后我们来看一下后方一致查询,选取出以字符串“ddd
”结尾的记录(代码清单 24)。
代码清单 24 使用 LIKE
进行后方一致查询
SELECT * FROM SampleLike
WHERE strcol LIKE "%ddd";
执行结果
strcol--------
abcddd
大家可以看到上述结果与前方一致正好相反。
此外,我们还可以使用 _
(下划线)来代替 %
,与 %
不同的是,它代表了“任意 1 个字符”。下面就让我们来尝试一下吧。
KEYWORD
_
使用代码清单 25 选取出 strcol
列的值为“abc
+ 任意 2 个字符”的记录。
代码清单 25 使用 LIKE
和 _
(下划线)进行前方一致查询
SELECT * FROM SampleLike
WHERE strcol LIKE "abc_ _";
执行结果
strcol--------
abcdd
“abcddd
”也是以“abc
”开头的字符串,但是其中“ddd
”是 3 个字符,所以不满足 __
所指定的 2 个字符的条件,因此该字符串并不在查询结果之中。相反,代码清单 26 中的 SQL 语句就只能取出“abcddd
”这个结果。
代码清单 26 查询“abc
+ 任意 3 个字符”的字符串
SELECT * FROM SampleLike
WHERE strcol LIKE "abc___";
执行结果
strcol--------
abcddd
三、BETWEEN
谓词——范围查询
使用 BETWEEN
可以进行范围查询。该谓词与其他谓词或者函数的不同之处在于它使用了 3 个参数。例如,从 product
(商品)表中读取出销售单价(sale_price
)为 100 日元到 1000 日元之间的商品时,可以使用代码清单 27 中的 SQL 语句。
KEYWORD
BETWEEN
谓词范围查询
代码清单 27 选取销售单价为 100 ~ 1000 日元的商品
SELECT product_name, sale_price FROM Product
WHERE sale_price BETWEEN 100 AND 1000;
执行结果
product_name | sale_price-----------0-+-------------
T恤衫 | 1000
打孔器 | 500
叉子 | 500
擦菜板 | 880
圆珠笔 | 100
BETWEEN
的特点就是结果中会包含 100 和 1000 这两个临界值。如果不想让结果中包含临界值,那就必须使用 <
和 >
(代码清单 28)。
KEYWORD
<
>
代码清单 28 选取出销售单价为 101 ~ 999 日元的商品
SELECT product_name, sale_price FROM Product
WHERE sale_price > 100
AND sale_price < 1000;
执行结果
product_name | sale_price-------------+-------------
打孔器 | 500
叉子 | 500
擦菜板 | 880
执行结果中不再包含 1000 日元和 100 日元的记录。
四、IS NULL
、IS NOT NULL
——判断是否为 NULL
为了选取出某些值为 NULL
的列的数据,不能使用 =
,而只能使用特定的谓词 IS NULL
(代码清单 29)。
KEYWORD
IS NULL
谓词
代码清单 29 选取出进货单价(purchase_price
)为 NULL
的商品
SELECT product_name, purchase_price FROM Product
WHERE purchase_price IS NULL;
执行结果
product_name | purchase_price-------------+-------------
叉子 |
圆珠笔 |
与此相反,想要选取 NULL
以外的数据时,需要使用 IS NOT NULL
(代码清单 30)。
KEYWORD
IS NOT NULL
谓词
代码清单 30 选取进货单价(purchase_price
)不为 NULL
的商品
SELECT product_name, purchase_price FROM Product
WHERE purchase_price IS NOT NULL;
执行结果
product_name | purchase_price-------------+---------------
T恤衫 | 500
打孔器 | 320
运动T恤 | 2800
菜刀 | 2800
高压锅 | 5000
擦菜板 | 790
五、IN
谓词——OR
的简便用法
接下来让我们思考一下如何选取出进货单价(purchase_price
)为 320 日元、500 日元、5000 日元的商品。这里使用之前学过的 OR
的 SQL 语句,请参考代码清单 31。
代码清单 31 通过 OR
指定多个进货单价进行查询
SELECT product_name, purchase_price FROM Product
WHERE purchase_price = 320
OR purchase_price = 500
OR purchase_price = 5000;
执行结果
product_name | purchase_price-------------+---------------
T恤衫 | 500
打孔器 | 320
高压锅 | 5000
虽然上述方法没有问题,但还是存在一点不足之处,那就是随着希望选取的对象越来越多,SQL 语句也会越来越长,阅读起来也会越来越困难。这时,我们就可以使用代码清单 32 中的 IN
谓词“IN( 值,……)
”来替换上述 SQL 语句。
KEYWORD
IN
谓词
代码清单 32 通过 IN
来指定多个进货单价进行查询
SELECT product_name, purchase_price FROM Product
WHERE purchase_price IN (320, 500, 5000);
反之,希望选取出“进货单价不是 320 日元、500 日元、5000 日元”的商品时,可以使用否定形式 NOT IN
来实现(代码清单 33)。
KEYWORD
NOT IN
谓词
代码清单 33 使用 NOT IN
进行查询时指定多个排除的进货单价进行查询
SELECT product_name, purchase_price FROM Product
WHERE purchase_price NOT IN (320, 500, 5000);
执行结果
product_name | purchase_price-------------+---------------
运动T恤 | 2800
菜刀 | 2800
擦菜板 | 790
但需要注意的是,在使用 IN
和 NOT IN
时是无法选取出 NULL
数据的。实际结果也是如此,上述两组结果中都不包含进货单价为 NULL
的叉子和圆珠笔。NULL
终究还是需要使用 IS NULL
和 IS NOT NULL
来进行判断。
六、使用子查询作为 IN
谓词的参数
6.1 IN
和子查询
IN
谓词(NOT IN
谓词)具有其他谓词所没有的用法,那就是可以使用子查询作为其参数。我们已经在 子查询 中学习过了,子查询就是 SQL 内部生成的表,因此也可以说“能够将表作为 IN
的参数”。同理,我们还可以说“能够将 视图 作为 IN
的参数”。
为了掌握详细的使用方法,让我们再添加一张新表。之前我们使用的全都是显示商品库存清单的 Product
(商品)表,但现实中这些商品可能只在个别的商店中进行销售。下面我们来创建表 2 ShopProduct
(商店商品),显示出哪些商店销售哪些商品。
表 2 ShopProduct
(商店商品)表
shop_id
(商店)shop_name
(商店名称)product_id
(商品编号)quantity
(数量)
000A
东京
0001
30
000A
东京
0002
50
000A
东京
0003
15
000B
名古屋
0002
30
000B
名古屋
0003
120
000B
名古屋
0004
20
000B
名古屋
0006
10
000B
名古屋
0007
40
000C
大阪
0003
20
000C
大阪
0004
50
000C
大阪
0006
90
000C
大阪
0007
70
000D
福冈
0001
100
商店和商品组合成为一条记录。例如,该表显示出东京店销售的商品有 0001(T 恤衫)、0002(打孔器)、0003(运动 T 恤)三种。
创建该表的 SQL 语句请参考代码清单 34。
代码清单 34 创建 ShopProduct
(商店商品)表的 CREATE TABLE
语句
CREATE TABLE ShopProduct(shop_id CHAR(4) NOT NULL,
shop_name VARCHAR(200) NOT NULL,
product_id CHAR(4) NOT NULL,
quantity INTEGER NOT NULL,
PRIMARY KEY (shop_id, product_id));
该 CREATE TABLE
语句的特点是指定了 2 列作为主键(primary key)。这样做当然还是为了区分表中每一行数据,由于单独使用商店编号(shop_id
)或者商品编号(product_id
)不能满足要求,因此需要对商店和商品进行组合。
实际上如果只使用商店编号进行区分,那么指定“000A
”作为条件能够查询出 3 行数据。而单独使用商品编号进行区分的话,“0001
”也会查询出 2 行数据,都无法恰当区分每行数据。
下面让我们来看一下向 ShopProduct
表中插入数据的 INSERT
语句(代码清单 35)。
代码清单 35 向 ShopProduct
表中插入数据的 INSERT
语句
SQL Server PostgreSQL
BEGIN TRANSACTION; --------①INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000A", "东京", "0001", 30);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000A", "东京", "0002", 50);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000A", "东京", "0003", 15);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000B", "名古屋", "0002", 30);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000B", "名古屋", "0003", 120);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000B", "名古屋", "0004", 20);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000B", "名古屋", "0006", 10);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000B", "名古屋", "0007", 40);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000C", "大阪", "0003", 20);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000C", "大阪", "0004", 50);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000C", "大阪", "0006", 90);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000C", "大阪", "0007", 70);
INSERT INTO ShopProduct (shop_id, shop_name, product_id, quantity) VALUES ("000D", "福冈", "0001", 100);
COMMIT;
特定的 SQL
不同的 DBMS 事务处理的语法也不尽相同。代码清单 35 在 MySQL 中执行时,需要将 ① 部分更改为“
START TRANSACTION;
”,在 Oracle 和 DB2 中执行时,无需用到 ① 的部分(请删除)。详细内容请大家参考 事务 中的“创建事务”。
这样我们就完成了全部准备工作,下面就让我们来看一看在 IN
谓词中使用子查询的 SQL 的写法吧。
首先读取出“大阪店(000C)在售商品(product_id
)的销售单价(sale_price
)”。
ShopProduct
(商店商品)表中大阪店的在售商品很容易就能找出,有如下 4 种。
运动 T 恤(商品编号 :0003)
菜刀(商品编号 :0004)
叉子(商品编号 :0006)
擦菜板(商品编号 :0007)
结果自然也应该是下面这样。
product_name | sale_price--------------+------------
运动T恤 | 4000
菜刀 | 3000
叉子 | 500
擦菜板 | 880
得到上述结果时,我们应该已经完成了如下两个步骤。
从
ShopProduct
表中选取出在大阪店(shop_id = "000C"
)中销售的商品(product_id
)从
Product
表中选取出上一步得到的商品(product_id
)的销售单价(sale_price
)
SQL 也是如此,同样要分两步来完成。首先,第一步如下所示。
SELECT product_id FROM ShopProduct
WHERE shop_id = "000C";
因为大阪店的商店编号(shop_id
)是“000C”,所以我们可以将其作为条件写在 WHERE
子句中 [1]。接下来,我们就可以把上述 SELECT
语句作为第二步中的条件来使用了。最终得到的 SELECT
语句请参考代码清单 36。
代码清单 36 使用子查询作为 IN
的参数
-- 取得“在大阪店销售的商品的销售单价”SELECT product_name, sale_price
FROM Product
WHERE product_id IN (SELECT product_id
FROM ShopProduct
WHERE shop_id = "000C");
执行结果
product_name | sale_price--------------+------------
叉子 | 500
运动T恤 | 4000
菜刀 | 3000
擦菜板 | 880
如 子查询 中的“法则 6”所述,子查询是从内层开始执行的。因此,该 SELECT
语句也是从内层的子查询开始执行,然后像下面这样展开。
-- 子查询展开后的结果SELECT product_name, sale_price
FROM Product
WHERE product_id IN ("0003", "0004", "0006", "0007");
这样就转换成了之前我们学习过的 IN
的使用方法了吧。可能有些读者会产生这样的疑问:“既然子查询展开后得到的结果同样是("0003","0004","0006","0007"),为什么一定要使用子查询呢?”
这是因为 ShopProduct
(商店商品)表并不是一成不变的。实际上由于各个商店销售的商品都在不断发生变化,因此 ShopProduct
表内大阪店销售的商品也会发生变化。如果 SELECT
语句中没有使用子查询的话,一旦商品发生了改变,那么 SELECT
语句也不得不进行修改,而且这样的修改工作会变得没完没了。
反之,如果在 SELECT
语句中使用了子查询,那么即使数据发生了变更,还可以继续使用同样的 SELECT
语句。这样也就减少了我们的常规作业(单纯的重复操作)。
像这样可以完美应对数据变更的程序称为“易维护程序”,或者“免维护程序”。这也是系统开发中需要重点考虑的部分。希望大家在开始学习编程时,就能够有意识地编写易于维护的代码。
6.2 NOT IN
和子查询
IN
的否定形式 NOT IN
同样可以使用子查询作为参数,其语法也和 IN
完全一样。请大家参考代码清单 37 中的例文。
代码清单 37 使用子查询作为 NOT IN
的参数
SELECT product_name, sale_price FROM Product
WHERE product_id NOT IN (SELECT product_id
FROM ShopProduct
WHERE shop_id = "000A");
本例中的 SQL 语句是要选取出“在东京店(000A)以外销售的商品(product_id
)的销售单价(sale_price
)”,“NOT IN
”代表了“以外”这样的否定含义。
我们也像之前那样来看一下该 SQL 的执行步骤。因为还是首先执行子查询,所以会得到如下结果。
-- 执行子查询SELECT product_name, sale_price
FROM Product
WHERE product_id NOT IN ("0001", "0002", "0003");
之后就很简单了,上述语句应该会返回 0001 ~ 0003 “以外”的结果。
执行结果
product_name | sale_price--------------+-----------
菜刀 | 3000
高压锅 | 6800
叉子 | 500
擦菜板 | 880
圆珠笔 | 100
七、EXISTS
谓词
本文最后将要给大家介绍的是 EXISTS
谓词。将它放到最后进行学习的原因有以下 3 点。
KEYWORD
EXISTS
谓词
① EXISTS
的使用方法与之前的都不相同
② 语法理解起来比较困难
③ 实际上即使不使用 EXISTS
,基本上也都可以使用 IN
(或者 NOT IN
)来代替
理由 ① 和 ② 都说明 EXISTS
是使用方法特殊而难以理解的谓词。特别是使用否定形式 NOT EXISTS
的 SELECT
语句,即使是 DB 工程师也常常无法迅速理解。此外,如理由 ③ 所述,使用 IN
作为替代的情况非常多(尽管不能完全替代让人有些伤脑筋),很多读者虽然记住了使用方法但还是不能实际运用。
但是一旦能够熟练使用 EXISTS
谓词,就能体会到它极大的便利性。因此,非常希望大家能够在达到 SQL 中级水平时掌握此工具。本文只简单介绍其基本使用方法 [2]。
接下来就让我们赶快看一看 EXISTS
吧。
7.1 EXISTS
谓词的使用方法
一言以蔽之,谓词的作用就是“判断是否存在满足某种条件的记录”。如果存在这样的记录就返回真(TRUE
),如果不存在就返回假(FALSE
)。 EXISTS
(存在)谓词的主语是“记录”。
我们继续使用前一节“IN
和子查询”中的示例,使用 EXISTS
选取出“大阪店(000C)在售商品(product_id
)的销售单价(sale_price
)”。
SELECT
语句请参考代码清单 38。
代码清单 38 使用 EXISTS
选取出“大阪店在售商品的销售单价”
SQL Server DB2 PostgreSQL MySQL
SELECT product_name, sale_price FROM Product AS P -----------------------①
WHERE EXISTS (SELECT *
FROM ShopProduct AS SP --②
WHERE SP.shop_id = "000C"
AND SP.product_id = P.product_id);
特定的 SQL
Oracle 的
FROM
子句中不能使用AS
(会发生错误)。因此,在 Oracle 中执行代码清单 38 时,请将 ① 的部分修改为“FROM Product P
”,将 ② 的部分修改为“FROM ShopProduct SP
”(删除FROM
子句中的AS
)
执行结果
product_name | sale_price-------------+-------------
叉子 | 500
运动T恤 | 4000
菜刀 | 3000
擦菜板 | 880
7.1.1 EXISTS
的参数
之前我们学过的谓词,基本上都是像“列 LIKE
字符串”或者“列 BETWEEN
值 1 AND
值 2”这样需要指定 2 个以上的参数,而 EXISTS
的左侧并没有任何参数。很奇妙吧?这是因为 EXISTS
是只有 1 个参数的谓词。EXISTS
只需要在右侧书写 1 个参数,该参数通常都会是一个子查询。
(SELECT * FROM ShopProduct AS SP
WHERE SP.shop_id = "000C"
AND SP.product_id = P.product_id)
上面这样的子查询就是唯一的参数。确切地说,由于通过条件“SP.product_id = P.product_id
”将 Product
表和 ShopProduct
表进行了联接,因此作为参数的是关联子查询。EXISTS
通常都会使用关联子查询作为参数 [3]。
法则 1
通常指定关联子查询作为
EXISTS
的参数。
7.1.2 子查询中的 SELECT *
可能大家会觉得子查询中的 SELECT *
稍微有些不同,就像我们之前学到的那样,由于 EXISTS
只关心记录是否存在,因此返回哪些列都没有关系。EXISTS
只会判断是否存在满足子查询中 WHERE
子句指定的条件“商店编号(shop_id
)为 "000C",商品(Product
)表和商店商品(ShopProduct
)表中商品编号(product_id
)相同”的记录,只有存在这样的记录时才返回真(TRUE
)。
因此,即使写成代码清单 39 那样,结果也不会发生改变。
代码清单 39 这样的写法也能得到与代码清单 38 相同的结果
SQL Server DB2 PostgreSQL MySQL
SELECT product_name, sale_price FROM Product AS P ------------------------------①
WHERE EXISTS (SELECT 1 -- 这里可以书写适当的常数
FROM ShopProduct AS SP ---------②
WHERE SP.shop_id = "000C"
AND SP.product_id = P.product_id);
特定的 SQL
在 Oracle 中执行代码清单 39 时,请将 ① 的部分修改为“
FROM Product P
”,将 ② 的部分修改为“FROM ShopProduct SP
”(删除FROM
子句中的AS
)。
大家可以把在 EXISTS
的子查询中书写 SELECT *
当作 SQL 的一种习惯。
法则 2
作为
EXISTS
参数的子查询中经常会使用SELECT *
。
7.1.3 使用 NOT EXISTS
替换 NOT IN
就像 EXISTS
可以用来替换 IN
一样,NOT IN
也可以用 NOT EXISTS
来替换。下面就让我们使用 NOT EXISTS
来编写一条 SELECT
语句,读取出“东京店(000A)在售之外的商品(product_id
)的销售单价(sale_price
)”(代码清单 40)。
KEYWORD
NOT EXISTS
谓词
代码清单 40 使用 NOT EXISTS
读取出“东京店在售之外的商品的销售单价”
SQL Server DB2 PostgreSQL MySQL
SELECT product_name, sale_price FROM Product AS P ----------------------------①
WHERE NOT EXISTS (SELECT *
FROM ShopProduct AS SP ---②
WHERE SP.shop_id = "000A"
AND SP.product_id = P.product_id);
特定的 SQL
在 Oracle 中执行代码清单 40 时,请将 ① 的部分修改为“
FROM Product P
”,将 ② 的部分修改为“FROM ShopProduct SP
”(删除FROM
子句中的AS
)。
执行结果
product_name | sale_price-------------+------------
菜刀 | 3000
高压锅 | 6800
叉子 | 500
擦菜板 | 880
圆珠笔 | 100
NOT EXISTS
与 EXISTS
相反,当“不存在”满足子查询中指定条件的记录时返回真(TRUE
)。
将 IN
(代码清单 36)和 EXISTS
(代码清单 38)的 SELECT
语句进行比较,会得到怎样的结果呢?可能大多数读者会觉得 IN
理解起来要容易一些,笔者也认为没有必要勉强使用 EXISTS
。因为 EXISTS
拥有 IN
所不具有的便利性,严格来说两者并不相同,所以希望大家能够在中级篇中掌握这两种谓词的使用方法。
请参阅
- 各种各样的函数
- SQL 谓词
- CASE 表达式
(完)
虽然使用“
shop_name="大阪"
”作为条件可以得到同样的结果,但是通常情况下,指定数据库中的商店或者商品时,并不会直接使用商品名称。这是因为与编号比起来,名称更有可能发生改变。 ↩︎希望了解
EXISTS
谓词详细内容的读者,可以参考《SQL进阶教程》中 1-8 节的内容。 ↩︎虽然严格来说语法上也可以使用非关联子查询作为参数,但实际应用中几乎没有这样的情况。 ↩︎
以上是 SQL谓词简介 的全部内容, 来源链接: utcz.com/z/536118.html