主頁 > 資料庫 > SQL 謂詞簡介

SQL 謂詞簡介

2021-12-07 08:03:24 資料庫

目錄
  • 一、什么是謂詞
  • 二、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
  • 請參閱

學習重點

  • 謂詞就是回傳值為真值的函式,

  • 掌握 LIKE 的三種使用方法(前方一致、中間一致、后方一致),

  • 需要注意 BETWEEN 包含三個引數,

  • 想要取得 NULL 資料時必須使用 IS NULL

  • 可以將子查詢作為 INEXISTS 的引數,

一、什么是謂詞

本文將會和大家一起學習 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 NULLIS 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

但需要注意的是,在使用 INNOT IN 時是無法選取出 NULL 資料的,實際結果也是如此,上述兩組結果中都不包含進貨單價為 NULL 的叉子和圓珠筆,NULL 終究還是需要使用 IS NULLIS 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 EXISTSSELECT 陳述句,即使是 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 EXISTSEXISTS 相反,當“不存在”滿足子查詢中指定條件的記錄時回傳真(TRUE),

IN(代碼清單 36)和 EXISTS(代碼清單 38)的 SELECT 陳述句進行比較,會得到怎樣的結果呢?可能大多數讀者會覺得 IN 理解起來要容易一些,筆者也認為沒有必要勉強使用 EXISTS,因為 EXISTS 擁有 IN 所不具有的便利性,嚴格來說兩者并不相同,所以希望大家能夠在中級篇中掌握這兩種謂詞的使用方法,

請參閱

  • 各種各樣的函式
  • SQL 謂詞
  • CASE 運算式

(完)


  1. 雖然使用“shop_name='大阪'”作為條件可以得到同樣的結果,但是通常情況下,指定資料庫中的商店或者商品時,并不會直接使用商品名稱,這是因為與編號比起來,名稱更有可能發生改變, ??

  2. 希望了解 EXISTS 謂詞詳細內容的讀者,可以參考《SQL進階教程》中 1-8 節的內容, ??

  3. 雖然嚴格來說語法上也可以使用非關聯子查詢作為引數,但實際應用中幾乎沒有這樣的情況, ??

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/374443.html

標籤:SQL Server

上一篇:SQL 中各種各樣的函式

下一篇:SQL CASE 運算式

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more