首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 流程控制函數實戰:CASE WHEN 與 IFNULL/COALESCE 深度對比

     編輯:MySQL 綜合教學

MySQL 流程控制函數實戰:CASE WHEN 與 IFNULL/COALESCE 深度對比

SQL 中的條件判斷是業務邏輯下推數據庫層的關鍵。MySQL 提供 CASE WHEN、IF()、IFNULL()、COALESCE()、NULLIF() 多種函數,本文通過實戰 UPDATE/SELECT 場景深度對比語法、語義、性能與適用邊界。

一、 CASE WHEN:通用條件分支

1. 簡單 CASE(值比較)

CASE col
    WHEN val1 THEN result1
    WHEN val2 THEN result2
    ELSE default_result
END

2. 搜索 CASE(布爾表達式)— 最常用

CASE 
    WHEN condition1 THEN result1
    WHEN condition2 THEN result2
    ELSE default_result
END

3. 實戰 UPDATE 場景:動態計算利潤

UPDATE t_tradefee 
SET margin_profit = CASE 
    WHEN market_price IS NULL THEN (2.3 - basic_fee) * remain_amount
    ELSE (2.3 - market_price) * remain_amount + margin_profit
END,
market_price = 2.3
WHERE SUBSTRING(cardno, 1, 3) = '001' 
  AND trade_type = 1;

語義:若無市場價(NULL),按基礎費率計算;否則按市場價調整並累加原利潤。

優勢:支持多條件、複雜表達式、嵌套、返回任意類型。

二、 IFNULL / COALESCE:空值處理專家

1. IFNULL(expr1, expr2) — 兩參數,MySQL 專有

  • expr1 NOT NULL → 返回 expr1
  • expr1 IS NULL → 返回 expr2
SELECT 
    DAY(op_time) AS day,
    SUM(price) AS price,
    IFNULL((
        SELECT SUM(price) 
        FROM t_margin_profit 
        WHERE op_time < '2016-01-01 00:00:00'
    ), 0) AS old_total
FROM t_margin_profit
WHERE YEAR(op_time) = 2016 AND MONTH(op_time) = 1
GROUP BY DAY(op_time);

場景:子查詢可能返回 NULL(無歷史數據),展示時轉為 0。

2. COALESCE(expr1, expr2, ..., exprN) — 多參數,標準 SQL

  • 返回第一個非 NULL 參數
  • 所有參數 NULL → 返回 NULL
-- 取第一個非空聯系方式
SELECT COALESCE(mobile, email, wechat, '未填寫') AS contact FROM users;

-- 多表關聯取優先非空字段
SELECT COALESCE(t1.name, t2.name, t3.name, '匿名') AS display_name
FROM main_table m
LEFT JOIN table1 t1 ON m.id = t1.mid
LEFT JOIN table2 t2 ON m.id = t2.mid
LEFT JOIN table3 t3 ON m.id = t3.mid;

3. IFNULL vs COALESCE 核心差異

維度IFNULLCOALESCE
參數個數固定 2 個1-N 個
標準兼容MySQL 專有ANSI SQL 標準
類型推導按 expr1/expr2 推導按所有參數最高優先級推導
短路求值支持支持
性能極微弱優勢(固定參數)通用

💡 選型建議:兩參數用 IFNULL(簡潔);多參數/跨庫遷移用 COALESCE。

三、 進階函數:IF / NULLIF

1. IF(condition, true_val, false_val) — 三元運算符

SELECT IF(score >= 60, '及格', '不及格') FROM exams;
-- 等價於 CASE WHEN score >= 60 THEN '及格' ELSE '不及格' END

⚠️ 注意:IF() 僅支持三參數,條件結果必須為標量。

2. NULLIF(expr1, expr2) — 相等則 NULL

-- 避免除零錯誤
SELECT 100 / NULLIF(divisor, 0) FROM calc;

-- 空字符串轉 NULL
SELECT NULLIF(trim(name), '') FROM users;

四、 綜合實戰:複雜業務邏輯下推

需求:訂單金額計算 — 會員折扣、滿減、優惠券疊加規則

SELECT 
    o.id,
    o.original_amount,
    -- 會員等級折扣
    CASE u.vip_level
        WHEN 1 THEN 0.95
        WHEN 2 THEN 0.90
        WHEN 3 THEN 0.85
        ELSE 1.00
    END AS vip_discount,
    -- 滿減:每滿 100 減 10
    FLOOR(o.original_amount / 100) * 10 AS full_reduction,
    -- 優惠券(取最大面額)
    COALESCE((
        SELECT MAX(coupon_value) 
        FROM user_coupons uc 
        WHERE uc.user_id = o.user_id 
          AND uc.status = 1 
          AND uc.expire_time > NOW()
    ), 0) AS coupon_value,
    -- 實付金額
    ROUND(
        o.original_amount * 
        CASE u.vip_level WHEN 1 THEN 0.95 WHEN 2 THEN 0.90 WHEN 3 THEN 0.85 ELSE 1.00 END
        - FLOOR(o.original_amount / 100) * 10
        - COALESCE((SELECT MAX(coupon_value) FROM user_coupons uc WHERE uc.user_id = o.user_id AND uc.status = 1 AND uc.expire_time > NOW()), 0)
    , 2) AS pay_amount
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 1;

五、 性能與優化建議

  1. 短路求值:CASE/IF/COALESCE 均支持,將高選擇性/低成本條件前置
  2. 避免隱式轉換:THEN/ELSE 返回類型保持一致,防止類型提升導致索引失效
  3. 子查詢優化:COALESCE((SELECT ...), 0) 確保子查詢返回單行單列,必要時加 LIMIT 1
  4. 大批量 UPDATE:分批次 LIMIT 1000 + SLEEP(0.1),避免長鎖表
  5. EXPLAIN 驗證:確認條件列有索引、無 Using temporary/Using filesort

六、 總結

CASE WHEN 是瑞士軍刀,處理複雜多路分支;IFNULL/COALESCE 是空值處理專用工具,語義清晰、可移植;IF/NULLIF 補充特定場景。實戰中遵循「語義最明確者優先、標準 SQL 優先、短路優化」原則,將業務判斷下推存儲層,減少應用層往返、提升吞吐。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved