目錄
- 一、什么是謂詞
- 二、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 節的內容, ??雖然嚴格來說語法上也可以使用非關聯子查詢作為引數,但實際應用中幾乎沒有這樣的情況, ??
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/374443.html
標籤:SQL Server
上一篇:SQL 中各種各樣的函式
下一篇:SQL CASE 運算式
