多條件組合查詢:邏輯運算符的應用

當單條件查詢無法滿足需求時,MySQL提供了三種邏輯運算符幫助我們組合多個條件:AND(與)、OR(或)、NOT(非)。這些運算符可以讓我們構建更精確的篩選條件,從數據中提取符合複雜規則的記錄。

AND運算符:同時滿足多個條件

AND運算符要求所有條件同時成立,返回的記錄必須滿足所有指定條件。其語法格式如下:

複製

SELECT 列名1, 列名2...
FROM 表名
WHERE 條件1 AND 條件2 [AND 條件3...];

實例應用:從員工表(employees)中查詢部門ID為30且薪資大於15000的員工信息:

複製

SELECT employee_id, first_name, last_name, department_id, salary
FROM employees
WHERE department_id = 30 AND salary > 15000;

預期結果:只會返回同時滿足"部門是30"和"薪資超過15000"兩個條件的員工記錄。

OR運算符:滿足任一條件

OR運算符允許記錄滿足多個條件中的任意一個即可被選中。語法格式如下:

複製

SELECT 列名1, 列名2...
FROM 表名
WHERE 條件1 OR 條件2 [OR 條件3...];

實例應用:查詢部門ID為30或者職位ID為66的員工信息:

複製

SELECT employee_id, first_name, last_name, department_id, job_id
FROM employees
WHERE department_id = 30 OR job_id = 66;

預期結果:返回所有屬於30部門的員工,以及所有職位ID為66的員工,包括那些既屬於30部門又是職位ID66的員工。

NOT運算符:排除滿足條件的記錄

NOT運算符用於否定其後的條件,返回不滿足該條件的記錄。語法格式如下:

複製

SELECT 列名1, 列名2...
FROM 表名
WHERE NOT 條件;

實例應用:查詢所有不在30部門的員工信息:

複製

SELECT employee_id, first_name, last_name, department_id
FROM employees
WHERE NOT department_id = 30;

等價寫法:上述查詢也可以用<>運算符實現:

複製

SELECT employee_id, first_name, last_name, department_id
FROM employees
WHERE department_id <> 30;

運算符優先級與括號的使用

當一個查詢中同時使用多個邏輯運算符時,MySQL會按照特定的優先級進行計算:NOT優先級最高,其次是AND,最後是OR。為了避免因優先級導致的意外結果,建議使用括號明確指定運算順序。

實例對比

不加括號的查詢(可能產生非預期結果):

複製

SELECT * FROM employees
WHERE department_id = 30 OR department_id = 50 AND salary > 20000;

由於AND優先級高於OR,上述查詢實際會先計算"department_id = 50 AND salary > 20000",然後再與"department_id = 30"進行OR運算。

加括號的明確查詢(推薦做法):

複製

SELECT * FROM employees
WHERE (department_id = 30 OR department_id = 50) AND salary > 20000;

這個查詢明確表示:先查找部門是30或50的員工,然後從中篩選出薪資大於20000的記錄。

範圍查詢:IN與BETWEEN操作符

當需要判斷某個字段的值是否在特定集合或範圍內時,使用IN和BETWEEN操作符可以使查詢語句更簡潔高效。

IN操作符:匹配多個離散值

IN操作符用於判斷字段值是否在指定的離散值列表中,相當於多個OR條件的組合,但語法更簡潔。

基本語法

複製

SELECT 列名1, 列名2...
FROM 表名
WHERE 列名 IN (值1, 值2, 值3...);

實例應用:查詢部門ID為30、50或80的員工信息:

複製

SELECT employee_id, first_name, last_name, department_id
FROM employees
WHERE department_id IN (30, 50, 80);

等價的OR條件寫法

複製

SELECT employee_id, first_name, last_name, department_id
FROM employees
WHERE department_id = 30 OR department_id = 50 OR department_id = 80;

NOT IN用法:查詢不在指定列表中的記錄:

複製

SELECT employee_id, first_name, last_name, department_id
FROM employees
WHERE department_id NOT IN (30, 50, 80);

注意事項

  • IN列表中的值必須具有相同的數據類型
  • IN操作符後的值列表最多可以包含65535個元素
  • IN操作符不能用於NULL值判斷,需要使用IS NULL或IS NOT NULL

BETWEEN操作符:匹配連續範圍內的值

BETWEEN操作符用於判斷字段值是否在某個連續的數值範圍或日期範圍內,包含範圍的起始值和結束值。

基本語法

複製

SELECT 列名1, 列名2...
FROM 表名
WHERE 列名 BETWEEN 起始值 AND 結束值;

數值範圍查詢實例:查詢薪資在10000到20000之間的員工信息:

複製

SELECT employee_id, first_name, last_name, salary
FROM employees
WHERE salary BETWEEN 10000 AND 20000;

等價的AND條件寫法

複製

SELECT employee_id, first_name, last_name, salary
FROM employees
WHERE salary >= 10000 AND salary <= 20000;

日期範圍查詢實例:查詢2005年1月1日到2005年12月31日期間入職的員工:

複製

SELECT employee_id, first_name, last_name, hire_date
FROM employees
WHERE hire_date BETWEEN '2005-01-01' AND '2005-12-31';

NOT BETWEEN用法:查詢薪資不在10000到20000之間的員工:

複製

SELECT employee_id, first_name, last_name, salary
FROM employees
WHERE salary NOT BETWEEN 10000 AND 20000;

注意事項

  • BETWEEN操作符是包含邊界值的(即包含起始值和結束值)
  • 使用時必須確保起始值小於結束值,否則會返回空結果
  • 對於日期類型,BETWEEN會精確到時間,如需按天查詢,建議使用日期函數

模糊查詢:LIKE操作符與通配符

當需要根據部分字符匹配來查找數據時,MySQL的LIKE操作符配合通配符可以實現強大的模糊查詢功能,非常適合處理文本搜索場景。

百分號(%)通配符:匹配任意字符序列

百分號(%)代表任意長度的字符序列(包括零個字符),是最常用的通配符。

基本語法

複製

SELECT 列名1, 列名2...
FROM 表名
WHERE 列名 LIKE '匹配模式';

實例1:以特定字符開頭 - 查詢名字以'A'開頭的員工:

複製

SELECT employee_id, first_name, last_name
FROM employees
WHERE first_name LIKE 'A%';

實例2:以特定字符結尾 - 查詢名字以'son'結尾的員工:

複製

SELECT employee_id, first_name, last_name
FROM employees
WHERE last_name LIKE '%son';

實例3:包含特定字符 - 查詢名字中包含'on'的員工:

複製

SELECT employee_id, first_name, last_name
FROM employees
WHERE first_name LIKE '%on%';

下劃線(_)通配符:匹配單個字符

下劃線(_)代表恰好一個任意字符,用於精確控制字符位置的匹配。

實例1:固定位置匹配 - 查詢名字長度為5個字符且第3個字符是't'的員工:

複製

SELECT employee_id, first_name, last_name
FROM employees
WHERE first_name LIKE '__t__'; -- 兩個下劃線 + t + 兩個下劃線

實例2:替換特定位置字符 - 查詢姓氏以'S'開頭、長度為5個字符的員工:

複製

SELECT employee_id, first_name, last_name
FROM employees
WHERE last_name LIKE 'S____'; -- S + 四個下劃線

方括號([])通配符:匹配指定集合中的單個字符

方括號([])用於匹配指定位置上的一個字符,該字符必須是方括號中列出的字符之一。注意:此通配符在MySQL中默認不啓用,需要使用REGEXP操作符才能實現類似功能。

使用REGEXP實現字符集匹配 - 查詢名字以'A'或'B'開頭的員工:

複製

SELECT employee_id, first_name, last_name
FROM employees
WHERE first_name REGEXP '^[AB]';

轉義字符:處理包含通配符的文本

當需要查詢的文本中本身包含%或_等特殊字符時,需要使用轉義字符(默認是\)來告訴MySQL將這些字符視為普通字符處理。

實例:查詢產品名稱中包含'%'字符的產品(如"20%折扣"):

複製

SELECT product_id, product_name
FROM products
WHERE product_name LIKE '%20\%折扣%'; -- 使用\轉義%

自定義轉義字符:如果查詢文本中包含\字符,可以使用ESCAPE子句自定義轉義字符:

複製

SELECT file_name
FROM documents
WHERE file_name LIKE '%\\report%' ESCAPE '\\'; -- 查詢包含\report的文件名

LIKE查詢的性能考量

雖然LIKE操作符功能強大,但過度使用可能影響查詢性能,特別是在大型表上。以下是一些性能優化建議:

  1. 避免以%開頭的模式:如LIKE '%abc'會導致全表掃描,無法使用索引
  2. 儘量使用最左前綴匹配:如LIKE 'abc%'可以利用索引
  3. 考慮全文搜索:對於複雜的文本搜索需求,MySQL的FULLTEXT索引比LIKE更高效
  4. 限制返回結果數量:使用LIMIT子句減少不必要的數據傳輸

NULL值處理:IS NULL與IS NOT NULL

在數據庫中,NULL代表"未知"或"不存在"的值,與空字符串('')和0截然不同。由於NULL的特殊性,不能使用常規的比較運算符(=、<>、>、<等)來判斷,必須使用專門的NULL值判斷語法。

NULL值的特性與比較規則

NULL值具有以下特殊特性,理解這些特性對於正確處理NULL值至關重要:

  1. NULL不等於任何值,包括它本身
  2. NULL與任何值運算的結果仍為NULL
  3. 對NULL使用聚合函數(如COUNT、SUM、AVG等)時,NULL會被忽略
  4. 排序時,NULL值被視為比任何非NULL值都小,默認排在最前面

IS NULL:查詢包含NULL值的記錄

使用IS NULL操作符可以篩選出指定列的值為NULL的記錄。

基本語法

複製

SELECT 列名1, 列名2...
FROM 表名
WHERE 列名 IS NULL;

實例應用:查詢沒有部門(department_id為NULL)的員工:

複製

SELECT employee_id, first_name, last_name, department_id
FROM employees
WHERE department_id IS NULL;

IS NOT NULL:查詢不包含NULL值的記錄

使用IS NOT NULL操作符可以篩選出指定列的值不為NULL的記錄。

基本語法

複製

SELECT 列名1, 列名2...
FROM 表名
WHERE 列名 IS NOT NULL;

實例應用:查詢有明確經理(manager_id不為NULL)的員工:

複製

SELECT employee_id, first_name, last_name, manager_id
FROM employees
WHERE manager_id IS NOT NULL;

NULL值在條件表達式中的處理

當NULL值出現在條件表達式中時,需要特別注意其邏輯結果:

實例1:NULL與AND組合

複製

SELECT * FROM employees
WHERE department_id = 30 AND commission_pct IS NULL;

上述查詢只會返回部門30中沒有佣金比例(commission_pct為NULL)的員工。

實例2:NULL與OR組合

複製

SELECT * FROM employees
WHERE salary > 20000 OR commission_pct IS NULL;

上述查詢會返回薪資超過20000的員工,以及所有沒有佣金比例的員工。

COALESCE函數:處理NULL值的替代方案

COALESCE函數可以返回參數列表中的第一個非NULL值,常用於將NULL值替換為特定的默認值。

基本語法

複製

COALESCE(表達式1, 表達式2, ..., 表達式n)

實例應用:查詢員工薪資,對於沒有佣金的員工,佣金部分顯示為0:

複製

SELECT
    employee_id,
    first_name,
    last_name,
    salary,
    COALESCE(commission_pct, 0) AS commission_pct
FROM employees;

實踐任務:高級條件查詢綜合練習

任務一:多條件組合查詢

需求:從員工表(employees)中查詢滿足以下條件的員工信息:

  • 部門ID為30或50
  • 薪資大於10000
  • 入職日期在2005年1月1日之後

SQL實現

複製

SELECT
    employee_id,
    first_name,
    last_name,
    department_id,
    salary,
    hire_date
FROM employees
WHERE
    (department_id = 30 OR department_id = 50)
    AND salary > 10000
    AND hire_date > '2005-01-01'
ORDER BY salary DESC;

預期結果:返回一個結果集,包含符合條件的員工記錄,按薪資降序排列。

任務二:IN與BETWEEN綜合應用

需求:從訂單表(orders)中查詢2006年的訂單,這些訂單的狀態必須是'Processing'、'Shipped'或'Delivered',並且訂單總金額在1000到5000之間。

SQL實現

複製

SELECT
    order_id,
    customer_id,
    order_date,
    status,
    total_amount
FROM orders
WHERE
    status IN ('Processing', 'Shipped', 'Delivered')
    AND total_amount BETWEEN 1000 AND 5000
    AND order_date BETWEEN '2006-01-01' AND '2006-12-31'
ORDER BY order_date;

預期結果:返回符合條件的2006年訂單記錄,包含訂單ID、客户ID、訂單日期、狀態和總金額等信息。

任務三:模糊查詢練習

需求:從產品表(products)中查詢滿足以下條件的產品:

  1. 產品名稱以'Wireless'開頭
  2. 產品描述中包含'bluetooth'(不區分大小寫)
  3. SKU編碼格式為'W-'開頭,後跟4個數字

SQL實現

複製

-- 1. 產品名稱以'Wireless'開頭
SELECT product_id, product_name, sku
FROM products
WHERE product_name LIKE 'Wireless%';

-- 2. 產品描述中包含'bluetooth'(不區分大小寫)
SELECT product_id, product_name, description
FROM products
WHERE description LIKE '%bluetooth%' OR description LIKE '%BLUETOOTH%';
-- 或者使用LOWER()函數實現不區分大小寫查詢(性能略低)
SELECT product_id, product_name, description
FROM products
WHERE LOWER(description) LIKE '%bluetooth%';

-- 3. SKU編碼格式為'W-'開頭,後跟4個數字
SELECT product_id, product_name, sku
FROM products
WHERE sku LIKE 'W-%____'; -- W- + 四個任意字符(假設數字)

預期結果:三個查詢分別返回符合不同模糊匹配條件的產品記錄。

任務四:NULL值處理練習

需求:從員工表(employees)中查詢所有員工的姓名、部門ID、經理ID和佣金比例,要求:

  1. 顯示所有沒有佣金的員工(commission_pct為NULL)
  2. 對於沒有經理的員工(manager_id為NULL),將經理ID顯示為'No Manager'
  3. 按部門ID排序,部門ID為NULL的員工排在最後

SQL實現

複製

SELECT
    first_name,
    last_name,
    department_id,
    COALESCE(CAST(manager_id AS CHAR), 'No Manager') AS manager_id,
    commission_pct
FROM employees
WHERE commission_pct IS NULL
ORDER BY
    CASE WHEN department_id IS NULL THEN 1 ELSE 0 END,
    department_id;

預期結果:返回所有沒有佣金的員工記錄,經理ID為NULL的顯示為'No Manager',結果按部門ID排序,無部門的員工排在最後。

任務五:綜合條件查詢挑戰

需求:從訂單明細表(order_details)中查詢滿足以下條件的訂單項:

  • 產品ID為10、20或30
  • 單價在100到500之間
  • 數量大於10
  • 折扣為0或者NULL
  • 按總價(單價×數量×(1-折扣))降序排列

SQL實現

複製

SELECT
    order_id,
    product_id,
    unit_price,
    quantity,
    discount,
    unit_price * quantity * (1 - COALESCE(discount, 0)) AS total_price
FROM order_details
WHERE
    product_id IN (10, 20, 30)
    AND unit_price BETWEEN 100 AND 500
  AND quantity > 10
    AND (discount = 0 OR discount IS NULL)
ORDER BY total_price DESC;

預期結果:返回符合所有條件的訂單項,包含計算出的總價,並按總價從高到低排序。

知識點總結與擴展

關鍵知識點回顧

  1. 邏輯運算符:AND(同時滿足)、OR(任一滿足)、NOT(否定條件),注意運算優先級和括號的使用
  2. 範圍查詢
  • IN:匹配多個離散值,語法簡潔,替代多個OR條件
  • BETWEEN:匹配連續範圍,包含邊界值,適用於數字和日期
  1. 模糊查詢
  • %:匹配任意長度字符序列
  • _:匹配單個字符
  • 轉義字符:處理包含通配符的文本
  1. NULL值處理
  • IS NULL/IS NOT NULL:判斷NULL值
  • COALESCE:返回第一個非NULL值
  • NULL與邏輯運算符的特殊交互

常見問題與解決方案

  1. 邏輯運算符優先級錯誤:解決方案是始終使用括號明確指定運算順序
  2. NULL值比較錯誤:記住不能使用=或<>判斷NULL,必須使用IS NULL/IS NOT NULL
  3. 模糊查詢性能問題:避免以%開頭的模式,考慮使用全文索引替代複雜LIKE查詢
  4. BETWEEN日期查詢包含時間部分:解決方案是使用DATE()函數或調整結束日期

進階學習方向

掌握了高級條件查詢後,你可以繼續學習以下相關主題:

  • 聚合函數與GROUP BY子句:對數據進行分組統計
  • HAVING子句:對分組結果進行篩選
  • 子查詢:在查詢中嵌套另一個查詢
  • 連接查詢:合併多個表的數據進行查詢

這些高級查詢技術將幫助你從數據庫中提取更有價值的信息,為數據分析和決策提供支持。明天我們將學習聚合函數與數據分組,進一步提升你的SQL查詢能力。