萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL 流程控制函數完全指南:CASE、IF、IFNULL、NULLIF 實戰

流程控制函數總覽

MySQL 提供四大流程控制函數,可在 SQL 查詢中實現條件邏輯,避免應用層往返:

  • CASE:多條件分支(兩種語法)
  • IF():簡單三元條件
  • IFNULL():NULL 替換
  • NULLIF():相等則回 NULL

CASE 運算式:兩種語法形式

1. 簡單 CASE(值比較)

CASE 值
    WHEN 比較值1 THEN 結果1
    WHEN 比較值2 THEN 結果2
    ...
    [ELSE 預設結果]
END

2. 搜尋 CASE(條件判斷)

CASE
    WHEN 條件1 THEN 結果1
    WHEN 條件2 THEN 結果2
    ...
    [ELSE 預設結果]
END

實戰範例

-- 簡單 CASE:成績等級
SELECT score,
       CASE score
           WHEN 100 THEN '完美'
           WHEN 90 THEN '優秀'
           ELSE '普通'
       END AS 等級
FROM exams;

-- 搜尋 CASE:區間判斷
SELECT score,
       CASE
           WHEN score >= 90 THEN 'A'
           WHEN score >= 80 THEN 'B'
           WHEN score >= 60 THEN 'C'
           ELSE 'D'
       END AS 等級
FROM exams;

-- 在 UPDATE 中使用
UPDATE products
SET status = CASE
    WHEN stock = 0 THEN '缺貨'
    WHEN stock < 10 THEN '庫存不足'
    ELSE '正常'
END;

回傳型別規則

  • 所有 THEN/ELSE 結果型別一致 → 該型別
  • 型別混合 → 數值語境轉數值,字串語境轉字串
  • 字串混合大小寫敏感 → 結果大小寫敏感

IF():三元運算子

IF(條件, 真值, 假值)

關鍵行為:條件以整數判斷真偽

SELECT IF(0.1, '真', '假');     -- '假'!0.1 轉整數為 0
SELECT IF(0.1 <> 0, '真', '假'); -- '真'  比較運算保留浮點精度

⚠️ 永遠使用比較運算子(<> 0, IS NOT NULL 等)而非直接放數值/字串。

實戰範例

-- 標記 VIP 客戶
SELECT name, 
       IF(total_spent > 10000, 'VIP', '一般') AS 客戶等級
FROM customers;

-- 安全除法(避免除零)
SELECT IF(divisor = 0, NULL, dividend / divisor) AS result
FROM calculations;

-- 巢狀 IF(不建議超過 2 層)
SELECT IF(score >= 90, 'A', IF(score >= 60, 'B', 'C')) AS grade;

IFNULL():NULL 替換專家

IFNULL(expr1, expr2)  -- expr1 不為 NULL 回傳 expr1,否則回傳 expr2

實戰範例

-- 顯示暱稱,無則顯示帳號
SELECT IFNULL(nickname, username) AS 顯示名稱 FROM users;

-- 計算總銷售額,無銷售記錄顯示 0
SELECT COALESCE(SUM(amount), 0) AS total_sales FROM orders WHERE user_id = 1;

-- IFNULL vs COALESCE:COALESCE 支援多參數,標準 SQL
SELECT COALESCE(mobile, phone, email, '無聯絡方式') FROM contacts;

NULLIF():相等歸零

NULLIF(expr1, expr2)  -- 相等回 NULL,否則回 expr1
-- 等價於 CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END

實戰範例

-- 避免除零錯誤(分母為 0 時回 NULL)
SELECT 100 / NULLIF(divisor, 0) FROM calculations;

-- 空字串轉 NULL(匯入清洗常用)
SELECT NULLIF(TRIM(name), '') FROM raw_data;

-- 移除特定預設值
SELECT NULLIF(status, 'default') FROM settings;

綜合實戰:動態報表欄位

SELECT 
    product_name,
    -- 庫存狀態
    CASE 
        WHEN stock = 0 THEN '缺貨'
        WHEN stock < reorder_level THEN '需補貨'
        ELSE '正常'
    END AS stock_status,
    -- 促銷價格(有促銷用促銷價,否則原價)
    IFNULL(promo_price, price) AS current_price,
    -- 折扣率(無折扣顯示 0)
    IFNULL(discount_rate, 0) AS discount,
    -- 利潤率(成本為 0 時回 NULL 避免除零)
    (price - cost) / NULLIF(cost, 0) * 100 AS profit_margin_pct
FROM products;

效能與最佳實務

  • CASE 可被優化器最佳化(常數摺疊、索引使用)
  • 避免在 WHERE 大量使用複雜 CASE,考慮計算欄位或應用層處理
  • IFNULL/COALESCE 在索引欄位上可能阻礙索引使用
  • NULLIF 防除零 比 IF(divisor=0, NULL, ...) 更簡潔
  • 巢狀層級:CASE 建議 ≤ 5 層,IF 建議 ≤ 2 層,超過請重構

PHP 整合範例

<?php
$conn = new mysqli("localhost", "user", "pass", "shop");

$sql = "SELECT 
    id, name, price,
    CASE 
        WHEN price > 1000 THEN '高價'
        WHEN price > 500 THEN '中價'
        ELSE '低價'
    END AS price_tier,
    IF(stock > 0, '有貨', '缺貨') AS availability,
    IFNULL(sale_price, price) AS final_price
FROM products
ORDER BY price_tier, final_price";

$result = $conn->query($sql);
while ($row = $result->fetch_assoc()) {
    echo "{$row['name']} | {$row['price_tier']} | {$row['availability']} | NT$ {$row['final_price']}
"; } $conn->close(); ?>

善用流程控制函數,讓 SQL 直觀表達業務邏輯,減少應用程式複雜度,提升查詢效能與可維護性!

copyright © 萬盛學電腦網 all rights reserved