本文 AI 產出,尚未審核
MySQL 課程 – 條件查詢
主題:WHERE 條件運算子
簡介
在資料庫開發與維運過程中,資料的篩選是最常見也是最重要的工作之一。WHERE 子句負責告訴 MySQL「只取出符合什麼條件的資料」,若沒有正確使用,可能會導致 資料遺漏、錯誤或效能低落。
本單元將從最常見的比較運算子、邏輯運算子、集合運算子、字串模式比對與 NULL 判斷,逐一說明其語法與實務應用,並提供多個可直接套用的範例,幫助讀者在日常開發中快速寫出正確且效能良好的查詢。
核心概念
1. 基本比較運算子
| 運算子 | 說明 | 範例 |
|---|---|---|
= |
等於 | price = 100 |
<>、!= |
不等於 | status <> 'active' |
> |
大於 | age > 30 |
>= |
大於或等於 | score >= 80 |
< |
小於 | quantity < 10 |
<= |
小於或等於 | created_at <= '2024-12-31' |
-- 範例 1:找出價格正好等於 100 元的商品
SELECT *
FROM products
WHERE price = 100;
/* 範例 2:找出年齡大於 30 歲且狀態為 'active' 的使用者 */
SELECT user_id, name, age
FROM users
WHERE age > 30 AND status = 'active';
/* 範例 3:找出庫存少於 10 件或已下架的商品 */
SELECT product_id, name, stock, discontinued
FROM inventory
WHERE stock < 10 OR discontinued = 1;
小技巧:若欄位上有索引,盡量使用
=、>、<、>=、<=等「範圍」比較,讓 MySQL 能利用索引加速搜尋。
2. 邏輯運算子
| 運算子 | 說明 | 範例 |
|---|---|---|
AND |
同時滿足兩個條件 | price > 50 AND stock > 0 |
OR |
任一條件成立即符合 | category = 'Books' OR category = 'Music' |
NOT |
取反,常與 IN、BETWEEN、LIKE 搭配 |
NOT (status = 'deleted') |
-- 範例 4:同時符合「價格大於 50」且「庫存大於 0」的商品
SELECT product_id, name, price, stock
FROM products
WHERE price > 50 AND stock > 0;
/* 範例 5:找出屬於「書籍」或「音樂」類別,且未被刪除的項目 */
SELECT *
FROM items
WHERE (category = 'Books' OR category = 'Music')
AND NOT deleted;
/* 範例 6:使用 NOT 搭配 BETWEEN,排除特定日期範圍 */
SELECT order_id, order_date, total
FROM orders
WHERE NOT order_date BETWEEN '2024-01-01' AND '2024-01-31';
注意:
AND的優先順序高於OR,必要時使用 括號 明確分組,避免邏輯錯誤。
3. 集合運算子
| 運算子 | 說明 | 範例 |
|---|---|---|
IN |
欄位值在給定集合內 | country IN ('TW', 'JP', 'KR') |
NOT IN |
欄位值不在集合內 | status NOT IN ('inactive', 'banned') |
BETWEEN … AND … |
範圍(含兩端) | price BETWEEN 100 AND 200 |
NOT BETWEEN |
範圍之外 | age NOT BETWEEN 18 AND 65 |
-- 範例 7:找出國家屬於台灣、日本或韓國的使用者
SELECT user_id, name, country
FROM users
WHERE country IN ('TW', 'JP', 'KR');
/* 範例 8:排除已停用或被封鎖的帳號 */
SELECT *
FROM accounts
WHERE status NOT IN ('inactive', 'banned');
/* 範例 9:搜尋價格介於 100~200 元的商品(含邊界) */
SELECT product_id, name, price
FROM products
WHERE price BETWEEN 100 AND 200;
最佳實踐:
IN列表若超過 10~15 個元素,建議改用臨時表或子查詢,避免產生過多的 OR 條件影響效能。
4. 字串模式比對
| 運算子 | 說明 | 範例 |
|---|---|---|
LIKE |
使用 %(任意字元)與 _(單一字元)做通配 |
name LIKE 'A%' |
NOT LIKE |
取反 | email NOT LIKE '%@example.com' |
REGEXP / RLIKE |
正規表達式比對,支援更複雜的模式 | phone REGEXP '^09[0-9]{8}$' |
-- 範例 10:找出姓名以「王」開頭的員工
SELECT employee_id, name
FROM employees
WHERE name LIKE '王%';
/* 範例 11:排除所有使用公司域名的 Email */
SELECT user_id, email
FROM users
WHERE email NOT LIKE '%@mycompany.com';
/* 範例 12:使用正規表達式驗證台灣手機號碼格式 */
SELECT customer_id, phone
FROM customers
WHERE phone REGEXP '^09[0-9]{8}$';
提醒:
LIKE在字串開頭使用通配符%(如'%abc')會導致全表掃描,效能最差。若必須前置通配,請考慮 全文索引(FULLTEXT) 或外部搜尋引擎。
5. NULL 判斷
| 運算子 | 說明 | 範例 |
|---|---|---|
IS NULL |
欄位值為 NULL | deleted_at IS NULL |
IS NOT NULL |
欄位值非 NULL | updated_at IS NOT NULL |
-- 範例 13:找出尚未被刪除的記錄
SELECT *
FROM posts
WHERE deleted_at IS NULL;
/* 範例 14:列出所有已更新過的使用者 */
SELECT user_id, last_login
FROM users
WHERE last_login IS NOT NULL;
關鍵概念:在 SQL 中,
NULL不是「空字串」或「0」,因此必須使用IS NULL/IS NOT NULL來比較,否則會得到 未知(UNKNOWN) 的結果。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
使用 = 比較 NULL |
col = NULL 永遠回傳 NULL(即不符合) |
改用 col IS NULL |
| 忘記加括號導致邏輯錯誤 | A OR B AND C 會先算 B AND C |
明確使用 (A OR B) AND C |
LIKE '%xxx' 產生全表掃描 |
前置 % 使索引失效 |
改用全文索引或正規表達式 |
IN 列表過長 |
MySQL 會把 IN 轉成大量 OR,效能下降 |
使用臨時表或 JOIN |
| 忽略資料類型差異 | int 欄位與字串比較可能產生隱式轉換 |
確保比較值型別一致,或使用 CAST |
使用 != 而非 <> |
雖然兩者皆可,但標準 SQL 推薦 <> |
建議統一使用 <>,提升可讀性 |
最佳實踐
- 盡量使用索引欄位作為
WHERE條件,避免在非索引欄位上做大量運算。 - 把條件拆成易讀的子句,例如使用 CTE(Common Table Expression)或子查詢,提高維護性。
- 在大型資料表上加入適當的覆寫索引(covering index),讓 MySQL 只走索引即可返回結果。
- 使用參數化查詢(prepared statements)防止 SQL Injection,同時讓執行計畫可重用。
實際應用場景
| 場景 | 需求 | WHERE 範例 |
|---|---|---|
| 電商商品搜尋 | 只顯示有庫存且價格在使用者指定範圍內的商品 | WHERE stock > 0 AND price BETWEEN 500 AND 2000 |
| 會員行為分析 | 找出過去 30 天內登入且未購買的使用者 | WHERE last_login >= CURDATE() - INTERVAL 30 DAY AND NOT EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id) |
| HR 員工篩選 | 取得部門為「研發」且年資大於 5 年的員工 | WHERE department = 'R&D' AND hire_date <= CURDATE() - INTERVAL 5 YEAR |
| 客服工單統計 | 統計本月未解決的工單數量 | WHERE status <> 'resolved' AND created_at BETWEEN DATE_FORMAT(CURDATE(),'%Y-%m-01') AND LAST_DAY(CURDATE()) |
| IoT 裝置監控 | 找出最近 5 分鐘內未回傳心跳的裝置 | WHERE last_heartbeat < NOW() - INTERVAL 5 MINUTE |
總結
WHERE 子句是 MySQL 條件查詢 的核心,正確掌握 比較、邏輯、集合、字串與 NULL 判斷 等運算子,能讓你快速定位所需資料,同時保持查詢效能。
- 先了解需求,再選擇最適合的運算子與寫法。
- 注意 運算子優先順序、索引使用與NULL 處理,可避免常見的陷阱。
- 透過 最佳實踐(如使用參數化查詢、合理建索引、適當分組條件),可讓程式碼更安全、易維護且效能佳。
掌握了這些概念,你就能在日常開發、資料分析與系統優化中,寫出 既正確又高效 的 MySQL 查詢。祝你在 MySQL 的世界裡玩得開心、查得順利!