SQL 謂詞簡介
- 一、什麼是謂詞
- 二、LIKE 謂詞——字串的部分一致查詢
- 三、BETWEEN 謂詞——範圍查詢
- 四、IS NULL、IS NOT NULL——判斷是否為 NULL
- 五、IN 謂詞——OR 的簡便用法
- 六、使用子查詢作為 IN 謂詞的引數
- 七、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
所不具有的便利性,嚴格來說兩者並不相同,所以希望大家能夠在中級篇中掌握這兩種謂詞的使用方法。
請參閱
(完)