Navicat Blog

使用 EXISTS 編寫 SELECT 查詢 2024 年 9 月 26 日,由 Robert Gravelle 撰寫

SQL 的 EXISTS 運算子為我們提供了一種根據某些其他資料的存在(或不存在)來擷取資料的簡單方法。更具體地說,它是一個邏輯運算子,用於評估子查詢的結果並傳回一個布林值(Boolean),指示是否傳回列。雖然 IN 運算子可用於類似的目的,但仍需要注意一些差異。本文將透過幾個範例介紹如何使用 EXISTS 運算子,並提供有關何時使用 EXISTS 而不是 IN 的一些指引。

使用 EXISTS 的範例

雖然 EXISTS 運算子可以在 SELECT、UPDATE、INSERT 或 DELETE 陳述式中使用,但為了簡單示範,我們將僅使用 SELECT 查詢。因此,我們將使用的語法將與以下類似:

SELECT column_name(s) 
FROM table_name
WHERE EXISTS ( SELECT column_name(s) 
               FROM table_name
               WHERE condition );

我們將對幾個可以在銀行資料庫中找到的 PostgreSQL 資料表(customer 和 account)執行查詢。以下是它們在 Navicat for PostgreSQL 的網格檢視中的模樣:

customer_table (29K)

account_table (28K)

現在我們可以使用以下查詢來查看所有擁有與其 customer_id 相關聯的帳戶的客戶:

SELECT *
FROM customer C
WHERE EXISTS ( SELECT *
               FROM account A
               WHERE C.customer_id = A.customer_id );

以下是上述查詢在 Navicat Premium 的查詢編輯器中的結果::

customers_with_accounts (49K)

將 NOT 與 EXISTS 一起使用

相反,在 EXISTS 運算子前面加上 NOT 關鍵字會導致查詢僅選取子查詢中沒有符合列的記錄。我們可以使用 NOT EXISTS 來取得所有孤立帳戶,即沒有關聯客戶的帳戶:

SELECT *
FROM account A
WHERE NOT EXISTS ( SELECT *
                   FROM customer C
                   WHERE A.customer_id = C.customer_id );

這查詢會傳回客戶 #4 的帳戶,因為在 customer 資料表中沒有該 ID 的客戶。

accounts_without_customers (47K)

將 EXISTS 替換為 JOIN

使用 EXISTS 運算子的查詢執行起來可能會有點慢,因為需要對外部查詢的每一行記錄執行子查詢。因此,你應該在可能的情況下考慮使用 JOIN。事實上,我們可以使用 LEFT JOIN 來重寫上述的 EXISTS 查詢:

SELECT C.*
FROM customer C
  LEFT JOIN account A ON C.customer_id = A.customer_id;
left_join (36K)

IN 與 EXISTS 運算子

儘管 IN 運算子通常用於篩選欄中特定列表的值,但它也可以應用於子查詢的結果。以下是相當於我們第一個查詢,但這次使用 IN 而不是 EXISTS:

SELECT * 
FROM customer 
WHERE customer_id IN (SELECT customer_id FROM account);

請注意,我們只能選取要比較的欄,而不是所有欄(SELECT *)。儘管如此,使用 IN 查詢會有相同的結果:

in_query (43K)

由於這兩個運算子非常相似,資料庫開發人員常常不確定應該使用哪一個。一般原則是,當你想要根據特定值列表篩選列時,應使用 IN 運算子。當你想要檢查子查詢中是否存在符合特定條件的列時,應使用 EXISTS。

總結

在今天的文章中,我們學習如何使用 EXISTS 運算子,以及如何決定是使用 EXISTS 還是 IN。

有興趣試用 Navicat Premium 17 嗎?你可以下載 14 天全功能的免費試用。它適用於 Windows、macOS 和 Linux 作業系統。

Navicat Blogs
Feed Entries
Blog Archives
Share