資料庫查詢的核心目的是從大量資料中精確擷取所需的資訊。WHERE 子句作為 SQL 查詢的關鍵組成部分,提供了豐富多樣的篩選機制,讓我們能夠根據各種條件精確地過濾資料。從簡單的相等比較到複雜的模式比對,從數值範圍檢查到集合成員判斷,這些篩選運算子共同構成了資料查詢的強大工具箱。

掌握各種篩選條件的特性和適用場景,不僅能幫助我們撰寫出功能正確的查詢,更能讓我們寫出效能優異的 SQL 語句。不同的篩選運算子在執行效率上可能存在顯著差異,某些寫法可以善用索引加速查詢,而另一些寫法則可能導致全表掃描。本文將深入探討各種篩選條件的語法、功能和效能特性,並透過實際案例說明如何選擇最適合的篩選策略。

集合運算子 IN 與 NOT IN

當我們需要檢查某個欄位的值是否屬於一組預定義的值時,IN 運算子提供了簡潔而直觀的語法。相較於使用多個 OR 條件,IN 運算子不僅程式碼更簡潔,在許多資料庫系統中執行效率也更高。

考慮一個葡萄酒資料庫的查詢場景。假設我們想要找出特定幾種葡萄品種的所有酒款:

-- 使用 IN 運算子查詢特定葡萄品種的酒款
-- 比使用多個 OR 條件更簡潔且效率更高
SELECT
    wine_id,
    wine_name,
    grape_variety,
    vintage_year,
    price
FROM wine
WHERE grape_variety IN ('Chardonnay', 'Riesling', 'Sauvignon Blanc')
ORDER BY grape_variety, vintage_year DESC;

這個查詢會傳回所有 grape_variety 為 Chardonnay、Riesling 或 Sauvignon Blanc 的酒款記錄。IN 運算子的等價寫法是使用多個 OR 條件:

-- 使用 OR 條件的等價寫法
-- 當條件數量增加時,可讀性會大幅降低
SELECT
    wine_id,
    wine_name,
    grape_variety,
    vintage_year,
    price
FROM wine
WHERE grape_variety = 'Chardonnay'
   OR grape_variety = 'Riesling'
   OR grape_variety = 'Sauvignon Blanc'
ORDER BY grape_variety, vintage_year DESC;

NOT IN 運算子則用於篩選不屬於指定集合的記錄。例如,如果我們想要找出除了 Chardonnay 和 Riesling 以外的所有葡萄酒類型:

-- 使用 NOT IN 排除特定的葡萄品種
-- 查詢所有不是 Chardonnay 和 Riesling 的酒款
SELECT
    wine_type_id,
    wine_type_name,
    description,
    typical_serving_temp
FROM wine_type
WHERE wine_type_name NOT IN ('Chardonnay', 'Riesling')
ORDER BY wine_type_name;

在使用 NOT IN 時需要特別注意 NULL 值的處理。如果 NOT IN 的列表中包含 NULL,或者被比較的欄位含有 NULL 值,可能會產生非預期的結果。這是因為任何值與 NULL 的比較結果都是 UNKNOWN,而非 TRUE 或 FALSE:

-- NOT IN 與 NULL 值的陷阱
-- 假設某些酒款的 grape_variety 為 NULL
SELECT wine_name
FROM wine
WHERE grape_variety NOT IN ('Chardonnay', NULL);  -- 這個查詢不會傳回任何結果!

-- 正確的處理方式:明確排除 NULL 值
SELECT wine_name
FROM wine
WHERE grape_variety NOT IN ('Chardonnay', 'Riesling')
  AND grape_variety IS NOT NULL;

IN 運算子還可以與子查詢結合使用,這是一種非常常見的應用模式:

-- 使用子查詢的 IN 運算子
-- 找出有獲獎記錄的酒莊所生產的所有酒款
SELECT
    w.wine_name,
    w.vintage_year,
    winery.winery_name
FROM wine w
INNER JOIN winery ON w.winery_id = winery.winery_id
WHERE w.winery_id IN (
    SELECT DISTINCT winery_id
    FROM wine_award
    WHERE award_year >= 2020
)
ORDER BY winery.winery_name, w.vintage_year;

範圍查詢 BETWEEN 與 NOT BETWEEN

BETWEEN 運算子提供了檢查數值或日期是否落在特定範圍內的簡潔語法。它是一個包含邊界的範圍檢查,等同於使用 >= 和 <= 的組合條件。

-- 使用 BETWEEN 查詢特定年份範圍出生的客戶
-- 查詢 1981 至 1996 年出生的千禧世代
SELECT
    customer_id,
    customer_name,
    birth_year,
    email,
    registration_date
FROM customer
WHERE birth_year BETWEEN 1981 AND 1996
ORDER BY birth_year, customer_name;

這個查詢等同於:

-- BETWEEN 的等價寫法
SELECT
    customer_id,
    customer_name,
    birth_year,
    email,
    registration_date
FROM customer
WHERE birth_year >= 1981 AND birth_year <= 1996
ORDER BY birth_year, customer_name;

BETWEEN 運算子在處理日期範圍查詢時特別實用:

-- 查詢特定日期範圍內的訂單
-- 包含起始日和結束日
SELECT
    order_id,
    customer_id,
    order_date,
    total_amount,
    status
FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-03-31'
ORDER BY order_date DESC;

需要注意的是,當 BETWEEN 用於日期時間欄位時,邊界值的處理可能因資料庫系統和欄位類型而異。如果欄位包含時間部分,使用 BETWEEN 時要特別小心:

-- 日期時間欄位的 BETWEEN 查詢
-- 可能會遺漏 2024-03-31 當天有時間部分的記錄
SELECT order_id, order_datetime
FROM orders
WHERE order_datetime BETWEEN '2024-01-01' AND '2024-03-31';

-- 更精確的寫法:使用 < 避免邊界問題
SELECT order_id, order_datetime
FROM orders
WHERE order_datetime >= '2024-01-01'
  AND order_datetime < '2024-04-01';

NOT BETWEEN 運算子用於篩選不在指定範圍內的記錄:

-- 使用 NOT BETWEEN 查詢非千禧世代的客戶
-- 包含 1981 年之前和 1996 年之後出生的客戶
SELECT
    customer_id,
    customer_name,
    birth_year,
    CASE
        WHEN birth_year < 1965 THEN 'Baby Boomer'
        WHEN birth_year BETWEEN 1965 AND 1980 THEN 'Generation X'
        WHEN birth_year > 1996 THEN 'Generation Z'
        ELSE 'Unknown'
    END AS generation
FROM customer
WHERE birth_year NOT BETWEEN 1981 AND 1996
ORDER BY birth_year;

BETWEEN 也可以用於字串的範圍比較,這在某些場景下很有用:

-- 查詢姓氏以 A 到 M 開頭的客戶
-- 字串比較基於字元的排序順序
SELECT customer_id, last_name, first_name
FROM customer
WHERE last_name BETWEEN 'A' AND 'M'
ORDER BY last_name;

模式比對 LIKE 與 NOT LIKE

LIKE 運算子是 SQL 中進行模式比對的主要工具。它支援兩種萬用字元:百分號(%)代表任意數量的字元(包括零個字元),底線(_)代表恰好一個任意字元。這兩種萬用字元的組合使得 LIKE 運算子能夠處理各種複雜的字串比對需求。

百分號萬用字元的應用

百分號萬用字元可以匹配任意長度的字元序列,包括空字串。根據百分號放置的位置不同,可以實現前綴匹配、後綴匹配或包含匹配:

-- 前綴匹配:查詢姓氏以 M 開頭的億萬富翁
-- 百分號放在模式末尾
SELECT
    billionaire_id,
    first_name,
    last_name,
    net_worth_billions,
    industry
FROM billionaire
WHERE last_name LIKE 'M%'
ORDER BY net_worth_billions DESC;

這個查詢會傳回所有 last_name 以 M 開頭的記錄,包括 Musk、Melnichenko、Ma 等姓氏。

-- 後綴匹配:查詢姓名以 son 結尾的人
-- 百分號放在模式開頭
SELECT
    billionaire_id,
    first_name,
    last_name
FROM billionaire
WHERE last_name LIKE '%son'
ORDER BY last_name;
-- 包含匹配:查詢姓氏中包含字母 e 的億萬富翁
-- 百分號放在模式兩端
SELECT
    billionaire_id,
    first_name,
    last_name,
    net_worth_billions
FROM billionaire
WHERE last_name LIKE '%e%'
ORDER BY last_name;

這個查詢會傳回所有姓氏中包含 e 的記錄,例如 Bezos、Gates、Melnichenko 等。

底線萬用字元的應用

底線萬用字元精確匹配一個字元,適用於已知字元數量但不確定具體字元的情況:

-- 查詢恰好三個字元且以 at 結尾的術語
-- 底線匹配第一個位置的任意字元
SELECT term_id, term, definition
FROM three_letter_term
WHERE term LIKE '_at'
ORDER BY term;

這個查詢會傳回如 cat、hat、mat、bat、rat 等符合模式的術語。

-- 查詢第二個字元為 a 的四字母單字
-- 結合底線和百分號萬用字元
SELECT word_id, word
FROM vocabulary
WHERE word LIKE '_a__'
ORDER BY word;

複合模式的應用

萬用字元可以組合使用來建立更複雜的比對模式:

-- 查詢電子郵件地址符合特定模式的客戶
-- 例如:第三個字元為 a,且域名為 gmail.com
SELECT
    customer_id,
    customer_name,
    email
FROM customer
WHERE email LIKE '__a%@gmail.com'
ORDER BY customer_name;

NOT LIKE 的應用

NOT LIKE 運算子用於排除符合特定模式的記錄:

-- 查詢姓氏不以 M 開頭的億萬富翁
SELECT
    billionaire_id,
    first_name,
    last_name,
    net_worth_billions
FROM billionaire
WHERE last_name NOT LIKE 'M%'
ORDER BY net_worth_billions DESC;
-- 查詢不以 at 結尾的三字母術語
SELECT term_id, term, definition
FROM three_letter_term
WHERE term NOT LIKE '_at'
ORDER BY term;

實際應用案例

讓我們看一個更複雜的實際應用案例。假設我們有一個音樂家資料表,需要查詢來自納什維爾地區的歌手。納什維爾的電話號碼區碼為 615 或 629:

-- 查詢納什維爾地區的歌手
-- 使用 LIKE 同時匹配音樂家類型和電話區碼
SELECT
    musician_id,
    musician_name,
    phone,
    musician_type,
    specialty
FROM musician
WHERE musician_type LIKE '%Singer%'      -- 類型包含 Singer
  AND (phone LIKE '615-%'                -- 電話以 615 開頭
       OR phone LIKE '629-%')            -- 或以 629 開頭
ORDER BY musician_name;

這個查詢展示了如何結合多個 LIKE 條件來實現複雜的篩選邏輯。注意使用括號來正確分組 OR 條件,否則可能產生非預期的結果。

效能考量

LIKE 運算子的效能特性需要特別關注。當百分號放在模式開頭時(如 ‘%text’),資料庫無法使用索引,必須進行全表掃描:

-- 效能較差:模式以 % 開頭,無法使用索引
SELECT * FROM customer WHERE email LIKE '%@gmail.com';

-- 效能較佳:模式以字元開頭,可以使用索引
SELECT * FROM customer WHERE email LIKE 'john%';

如果經常需要進行後綴或包含搜尋,可以考慮以下最佳化策略:

-- 建立反轉欄位以支援後綴搜尋
ALTER TABLE customer ADD COLUMN email_reversed VARCHAR(255);
UPDATE customer SET email_reversed = REVERSE(email);
CREATE INDEX idx_email_reversed ON customer(email_reversed);

-- 使用反轉欄位進行後綴搜尋
SELECT * FROM customer
WHERE email_reversed LIKE REVERSE('%@gmail.com');
-- 等同於 WHERE email_reversed LIKE 'moc.liamg@%'
@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

rectangle "LIKE 運算子效能分析" as title

rectangle "可使用索引" as good {
    rectangle "LIKE 'prefix%'"
    rectangle "模式以固定字元開頭"
    rectangle "效能較佳"
}

rectangle "無法使用索引" as bad {
    rectangle "LIKE '%suffix'"
    rectangle "LIKE '%contain%'"
    rectangle "需要全表掃描"
}

good -[hidden]right-> bad

note bottom of good
適用場景:
前綴搜尋
首字母篩選
end note

note bottom of bad
最佳化建議:
使用全文索引
建立反轉欄位
考慮搜尋引擎
end note

@enduml

EXISTS 存在性檢查

EXISTS 運算子用於檢查子查詢是否傳回至少一筆記錄。與 IN 運算子不同,EXISTS 只關心子查詢是否有結果,而不關心具體的值。這個特性使得 EXISTS 在某些場景下比 IN 更有效率。

-- 使用 EXISTS 檢查是否存在千禧世代客戶
-- EXISTS 只檢查是否有記錄,不關心具體內容
SELECT '客戶資料庫中至少有一位千禧世代' AS message
WHERE EXISTS (
    SELECT 1
    FROM customer
    WHERE birth_year BETWEEN 1981 AND 1996
);

如果 customer 表中存在至少一位出生年份在 1981 到 1996 之間的客戶,查詢會傳回該訊息;否則不會傳回任何結果。

EXISTS 的一個重要特性是它不關心子查詢傳回的具體內容,只關心是否有記錄。因此,在子查詢中使用 SELECT 1 或 SELECT * 效果相同:

-- 以下兩個查詢完全等效
-- EXISTS 只檢查是否有記錄存在

-- 寫法一:SELECT *
SELECT '有千禧世代客戶' AS result
WHERE EXISTS (
    SELECT *
    FROM customer
    WHERE birth_year BETWEEN 1981 AND 1996
);

-- 寫法二:SELECT 1(建議使用)
SELECT '有千禧世代客戶' AS result
WHERE EXISTS (
    SELECT 1
    FROM customer
    WHERE birth_year BETWEEN 1981 AND 1996
);

EXISTS 最常見的應用是與相關子查詢(Correlated Subquery)結合使用,用於檢查關聯條件:

-- 查詢有下過訂單的客戶
-- 使用相關子查詢的 EXISTS
SELECT
    c.customer_id,
    c.customer_name,
    c.email
FROM customer c
WHERE EXISTS (
    SELECT 1
    FROM orders o
    WHERE o.customer_id = c.customer_id  -- 相關條件
)
ORDER BY c.customer_name;

NOT EXISTS 則用於查詢不存在關聯記錄的情況:

-- 查詢從未下過訂單的客戶
-- 使用 NOT EXISTS
SELECT
    c.customer_id,
    c.customer_name,
    c.email,
    c.registration_date
FROM customer c
WHERE NOT EXISTS (
    SELECT 1
    FROM orders o
    WHERE o.customer_id = c.customer_id
)
ORDER BY c.registration_date;

EXISTS 與 IN 的比較

EXISTS 和 IN 在許多情況下可以達成相同的效果,但它們的效能特性有所不同:

-- 使用 IN 的寫法
SELECT c.customer_id, c.customer_name
FROM customer c
WHERE c.customer_id IN (
    SELECT o.customer_id
    FROM orders o
    WHERE o.order_date >= '2024-01-01'
);

-- 使用 EXISTS 的等效寫法
SELECT c.customer_id, c.customer_name
FROM customer c
WHERE EXISTS (
    SELECT 1
    FROM orders o
    WHERE o.customer_id = c.customer_id
      AND o.order_date >= '2024-01-01'
);

一般而言,當子查詢的結果集較大時,EXISTS 的效能通常較佳;當子查詢的結果集較小時,IN 的效能可能較佳。現代資料庫最佳化器通常能夠自動選擇最佳的執行計劃,但了解這些差異有助於在效能調校時做出正確的決策。

@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

rectangle "EXISTS 運算子工作原理" as title

package "執行流程" {
    rectangle "1. 對外層查詢的每一列" as step1
    rectangle "2. 執行子查詢" as step2
    rectangle "3. 檢查是否有結果" as step3
    rectangle "4. 有結果則保留該列" as step4
    
    step1 -down-> step2
    step2 -down-> step3
    step3 -down-> step4
}

package "特性" {
    rectangle "找到第一筆即停止" as f1
    rectangle "不關心實際傳回值" as f2
    rectangle "適合相關子查詢" as f3
    rectangle "NULL 值處理安全" as f4
    
    f1 -down[hidden]-> f2
    f2 -down[hidden]-> f3
    f3 -down[hidden]-> f4
}

title -down-> "執行流程"
title -down-> "特性"

@enduml

布林值欄位的檢查

布林值是一種只有兩個可能值的資料類型:TRUE(真)或 FALSE(假)。在不同的資料庫系統中,布林值的內部表示方式可能有所不同。MySQL 使用 TINYINT(1) 來儲存布林值,其中 1 代表 TRUE,0 代表 FALSE。

基本的布林值檢查

檢查布林值欄位最直接的方式是使用 IS TRUE 和 IS FALSE:

-- 建立包含布林值欄位的員工資料表
CREATE TABLE employee (
    employee_id INT PRIMARY KEY,
    employee_name VARCHAR(100),
    department VARCHAR(50),
    is_manager BOOLEAN,                -- 是否為主管
    is_active BOOLEAN DEFAULT TRUE,    -- 是否在職
    has_parking BOOLEAN                -- 是否有停車位
);

-- 查詢所有在職的主管
SELECT
    employee_id,
    employee_name,
    department
FROM employee
WHERE is_manager IS TRUE
  AND is_active IS TRUE
ORDER BY department, employee_name;

多種等效的檢查方式

SQL 提供了多種檢查布林值的等效語法。了解這些不同的寫法有助於閱讀他人的程式碼,以及根據情況選擇最適合的方式:

-- 檢查 TRUE 值的各種等效寫法
-- 所有以下條件都檢查 is_active 為 TRUE

-- 寫法 1:使用 IS TRUE(最明確)
SELECT * FROM employee WHERE is_active IS TRUE;

-- 寫法 2:直接使用欄位名稱(最簡潔)
SELECT * FROM employee WHERE is_active;

-- 寫法 3:使用等於運算子
SELECT * FROM employee WHERE is_active = TRUE;

-- 寫法 4:使用不等於 FALSE
SELECT * FROM employee WHERE is_active != FALSE;

-- 寫法 5:使用數值 1
SELECT * FROM employee WHERE is_active = 1;

-- 寫法 6:使用不等於 0
SELECT * FROM employee WHERE is_active != 0;
-- 檢查 FALSE 值的各種等效寫法

-- 寫法 1:使用 IS FALSE(最明確)
SELECT * FROM employee WHERE is_manager IS FALSE;

-- 寫法 2:使用 NOT 運算子(較常用)
SELECT * FROM employee WHERE NOT is_manager;

-- 寫法 3:使用等於運算子
SELECT * FROM employee WHERE is_manager = FALSE;

-- 寫法 4:使用不等於 TRUE
SELECT * FROM employee WHERE is_manager != TRUE;

-- 寫法 5:使用數值 0
SELECT * FROM employee WHERE is_manager = 0;

-- 寫法 6:使用不等於 1
SELECT * FROM employee WHERE is_manager != 1;

NULL 值的處理

布林值欄位可能包含 NULL 值,這需要特別處理。IS TRUE 和 IS FALSE 會明確排除 NULL 值,而其他寫法的行為可能有所不同:

-- 假設 has_parking 欄位可能為 NULL
-- 查詢有停車位的員工(排除 NULL)
SELECT employee_name
FROM employee
WHERE has_parking IS TRUE;

-- 查詢沒有停車位或未知的員工
SELECT employee_name
FROM employee
WHERE has_parking IS NOT TRUE;  -- 包含 FALSE 和 NULL

-- 查詢明確沒有停車位的員工(排除 NULL)
SELECT employee_name
FROM employee
WHERE has_parking IS FALSE;

-- 查詢停車位狀態未知的員工
SELECT employee_name
FROM employee
WHERE has_parking IS NULL;

實際應用案例

讓我們看一個結合多個布林條件的實際查詢:

-- 查詢符合特定條件的員工
-- 條件:在職、非主管、有停車位
SELECT
    e.employee_id,
    e.employee_name,
    e.department,
    CASE WHEN e.is_manager THEN '是' ELSE '否' END AS is_manager_display,
    CASE WHEN e.has_parking THEN '有' ELSE '無' END AS parking_status
FROM employee e
WHERE e.is_active IS TRUE
  AND e.is_manager IS FALSE
  AND e.has_parking IS TRUE
ORDER BY e.department, e.employee_name;

在效能方面,直接使用欄位名稱(如 WHERE is_active)通常與使用 IS TRUE 的效能相同,因為資料庫最佳化器會將它們視為等效條件。然而,為了程式碼的可讀性和明確性,建議在需要強調布林檢查時使用 IS TRUE 和 IS FALSE 語法。

綜合應用與效能最佳化

在實際應用中,我們經常需要結合多種篩選條件來完成複雜的查詢需求。以下是一些綜合應用的範例和效能最佳化建議。

複合條件的組合

-- 綜合應用範例:篩選符合多重條件的客戶
-- 結合 IN、BETWEEN、LIKE 和布林值檢查
SELECT
    c.customer_id,
    c.customer_name,
    c.email,
    c.birth_year,
    c.membership_level,
    c.is_active
FROM customer c
WHERE c.membership_level IN ('Gold', 'Platinum')           -- 會員等級篩選
  AND c.birth_year BETWEEN 1980 AND 1995                  -- 年齡範圍篩選
  AND c.email LIKE '%@gmail.com'                          -- 電子郵件模式篩選
  AND c.is_active IS TRUE                                 -- 活躍狀態篩選
  AND NOT EXISTS (                                        -- 排除有未付款訂單的客戶
      SELECT 1
      FROM orders o
      WHERE o.customer_id = c.customer_id
        AND o.payment_status = 'Pending'
  )
ORDER BY c.customer_name;

效能最佳化策略

選擇篩選條件時,除了功能正確性外,效能也是重要的考量因素:

-- 建立適當的索引以支援篩選條件
CREATE INDEX idx_customer_membership ON customer(membership_level);
CREATE INDEX idx_customer_birth_year ON customer(birth_year);
CREATE INDEX idx_customer_active ON customer(is_active);
CREATE INDEX idx_orders_customer_status ON orders(customer_id, payment_status);

-- 複合索引可以支援多個條件的查詢
CREATE INDEX idx_customer_active_level ON customer(is_active, membership_level);
-- 條件順序的最佳化
-- 將選擇性高(過濾效果好)的條件放在前面
SELECT *
FROM customer
WHERE is_active IS TRUE              -- 先過濾大量不活躍用戶
  AND membership_level = 'Platinum'  -- 再過濾少數高級會員
  AND email LIKE 'a%';               -- 最後做模式比對

避免常見的效能陷阱

-- 陷阱 1:在索引欄位上使用函數
-- 不佳:無法使用索引
SELECT * FROM customer WHERE YEAR(registration_date) = 2024;

-- 較佳:使用範圍查詢
SELECT * FROM customer
WHERE registration_date >= '2024-01-01'
  AND registration_date < '2025-01-01';

-- 陷阱 2:使用 OR 連接不同欄位
-- 可能無法有效使用索引
SELECT * FROM customer
WHERE email LIKE 'john%' OR phone LIKE '02-%';

-- 較佳:使用 UNION
SELECT * FROM customer WHERE email LIKE 'john%'
UNION
SELECT * FROM customer WHERE phone LIKE '02-%';

-- 陷阱 3:NOT IN 與 NULL 值
-- 可能產生非預期結果
SELECT * FROM customer WHERE customer_id NOT IN (SELECT customer_id FROM banned_list);

-- 較佳:使用 NOT EXISTS 或明確處理 NULL
SELECT * FROM customer c
WHERE NOT EXISTS (
    SELECT 1 FROM banned_list b WHERE b.customer_id = c.customer_id
);

掌握 SQL 篩選查詢的各種運算子和技巧,是成為高效資料庫開發者的基礎。從基本的比較運算到複雜的存在性檢查,每種篩選方式都有其特定的應用場景和效能特性。IN 和 NOT IN 適合集合成員判斷,BETWEEN 適合範圍查詢,LIKE 適合模式比對,EXISTS 適合存在性檢查,而布林值檢查則提供了多種等效語法供選擇。

在實務應用中,選擇適當的篩選方式不僅要考慮功能正確性,還要考慮查詢效能。了解各種運算子對索引的影響,避免常見的效能陷阱,並善用資料庫提供的最佳化工具,是撰寫高效 SQL 查詢的關鍵。透過不斷的實踐和經驗累積,我們可以逐漸培養出在各種情境下選擇最佳篩選策略的能力。