MySQL 提供 IF()、CASE、IFNULL()、NULLIF() 四大流程控制函數,讓查詢具備條件邏輯能力。本文系統整理語法、型別推導規則、實戰範例、效能陷阱與最佳實踐,助你在正確場景用好它們。
| 函數 | 語法 | 回傳型別規則 | 核心行為 |
|---|---|---|---|
IF(expr1, expr2, expr3) | expr1 為真(非 0/非 NULL)回傳 expr2,否則 expr3 | expr2/expr3 型別較高者:STRING > REAL > INTEGER | 單條件三元運算 |
CASE 值 WHEN 比較值 THEN 結果 ... [ELSE 結果] END | 所有 THEN/ELSE 結果型別的通用集合 | 值比較模式(類 switch) | |
CASE WHEN 條件 THEN 結果 ... [ELSE 結果] END | 同上 | 條件判斷模式(類 if-else 鏈) | |
IFNULL(expr1, expr2) | expr1 不為 NULL 回傳 expr1,否則 expr2 | 兩者通用型別 | NULL 替換捷徑 |
NULLIF(expr1, expr2) | expr1 = expr2 回傳 NULL,否則 expr1 | expr1 型別 | 相等則 NULL,防除零錯誤 |
-- 性別碼轉換
SELECT name, IF(sex=1, '男', '女') AS gender FROM users;
-- 動態排序:參數 @sort_desc=1 降序,0 升序
SELECT * FROM products ORDER BY IF(@sort_desc=1, price, -price);
-- 條件聚合:統計各狀態訂單數
SELECT
SUM(IF(status=1, 1, 0)) AS paid_count,
SUM(IF(status=2, 1, 0)) AS shipped_count,
SUM(IF(status=3, 1, 0)) AS refund_count
FROM orders;
-- 價格區間分桶
SELECT
CASE
WHEN price < 100 THEN '低價'
WHEN price < 500 THEN '中價'
WHEN price < 1000 THEN '高價'
ELSE '奢華'
END AS price_tier,
COUNT(*) AS cnt
FROM products GROUP BY price_tier;
-- 除零保護:NULLIF 讓分母為 0 時回傳 NULL,結果為 NULL 而非報錯
SELECT total_amount / NULLIF(order_count, 0) AS avg_order_value FROM sales;
-- 單欄位預設
SELECT IFNULL(phone, '未填寫') AS contact FROM users;
-- 多欄位取首個非空(COALESCE 為標準 SQL,支援 N 參數)
SELECT COALESCE(mobile, office_phone, home_phone, '無聯繫方式') AS contact FROM users;
-- 危險:IF 回傳字串,where 欄位為數字 → 隱式轉換 → 全表掃描
SELECT * FROM orders WHERE IF(status=1, 'paid', 'unpaid') = 'paid'; -- 錯誤示範
-- 正確:保持型別一致
SELECT * FROM orders WHERE status = 1;
鐵律:流程控制函數不要用在 WHERE/JOIN/INDEX 條件欄位上,僅用於 SELECT 列表、ORDER BY、GROUP BY、HAVING。
| 場景 | 建議 | 理由 |
|---|---|---|
| SELECT 列表轉換展示值 | ✅ 推薦 | 應用層省去轉換邏輯,網路傳輸量不增 |
| 條件聚合 | ✅ 推薦 | 單掃描完成多維統計,避免多次查詢 |
| 動態排序/分組 | ⚠️ 謹慎 | 可能導致 filesort,大資料集測試後再用 |
| WHERE/JOIN 條件 | ❌ 禁止 | 破壞索引使用,隱式轉換,優化器無法推導 |
| 大表計算欄位 | ❌ 避免 | CPU 開銷大,考慮物化視圖/應用層計算 |
-- 表達式(查詢中用):回傳值
SELECT CASE WHEN x>0 THEN '正' ELSE '非正' END;
-- 陳述式(預存程序中用):控制流程,不回傳值
CASE
WHEN v_action = 'insert' THEN INSERT ...;
WHEN v_action = 'update' THEN UPDATE ...;
ELSE SELECT 'invalid action';
END CASE;
MySQL 流程控制函數是「查詢層小邏輯」的利器,用好能減少應用層往返、簡化報表 SQL、實現條件聚合。但嚴禁滲透到 WHERE/JOIN/索引欄位,否則效能災難立現。記住:CASE WHEN 處理多條件,IF() 處理單條件三元,COALESCE() 處理多欄位取首非空,NULLIF() 專治除零——各司其職,方為正道。