多條件組合查詢:邏輯運算符的應用
當單條件查詢無法滿足需求時,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操作符功能強大,但過度使用可能影響查詢性能,特別是在大型表上。以下是一些性能優化建議:
- 避免以%開頭的模式:如LIKE '%abc'會導致全表掃描,無法使用索引
- 儘量使用最左前綴匹配:如LIKE 'abc%'可以利用索引
- 考慮全文搜索:對於複雜的文本搜索需求,MySQL的FULLTEXT索引比LIKE更高效
- 限制返回結果數量:使用LIMIT子句減少不必要的數據傳輸
NULL值處理:IS NULL與IS NOT NULL
在數據庫中,NULL代表"未知"或"不存在"的值,與空字符串('')和0截然不同。由於NULL的特殊性,不能使用常規的比較運算符(=、<>、>、<等)來判斷,必須使用專門的NULL值判斷語法。
NULL值的特性與比較規則
NULL值具有以下特殊特性,理解這些特性對於正確處理NULL值至關重要:
- NULL不等於任何值,包括它本身
- NULL與任何值運算的結果仍為NULL
- 對NULL使用聚合函數(如COUNT、SUM、AVG等)時,NULL會被忽略
- 排序時,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)中查詢滿足以下條件的產品:
- 產品名稱以'Wireless'開頭
- 產品描述中包含'bluetooth'(不區分大小寫)
- 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和佣金比例,要求:
- 顯示所有沒有佣金的員工(commission_pct為NULL)
- 對於沒有經理的員工(manager_id為NULL),將經理ID顯示為'No Manager'
- 按部門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;
預期結果:返回符合所有條件的訂單項,包含計算出的總價,並按總價從高到低排序。
知識點總結與擴展
關鍵知識點回顧
- 邏輯運算符:AND(同時滿足)、OR(任一滿足)、NOT(否定條件),注意運算優先級和括號的使用
- 範圍查詢:
- IN:匹配多個離散值,語法簡潔,替代多個OR條件
- BETWEEN:匹配連續範圍,包含邊界值,適用於數字和日期
- 模糊查詢:
- %:匹配任意長度字符序列
- _:匹配單個字符
- 轉義字符:處理包含通配符的文本
- NULL值處理:
- IS NULL/IS NOT NULL:判斷NULL值
- COALESCE:返回第一個非NULL值
- NULL與邏輯運算符的特殊交互
常見問題與解決方案
- 邏輯運算符優先級錯誤:解決方案是始終使用括號明確指定運算順序
- NULL值比較錯誤:記住不能使用=或<>判斷NULL,必須使用IS NULL/IS NOT NULL
- 模糊查詢性能問題:避免以%開頭的模式,考慮使用全文索引替代複雜LIKE查詢
- BETWEEN日期查詢包含時間部分:解決方案是使用DATE()函數或調整結束日期
進階學習方向
掌握了高級條件查詢後,你可以繼續學習以下相關主題:
- 聚合函數與GROUP BY子句:對數據進行分組統計
- HAVING子句:對分組結果進行篩選
- 子查詢:在查詢中嵌套另一個查詢
- 連接查詢:合併多個表的數據進行查詢
這些高級查詢技術將幫助你從數據庫中提取更有價值的信息,為數據分析和決策提供支持。明天我們將學習聚合函數與數據分組,進一步提升你的SQL查詢能力。