一、SQL 語句級條件表達式(可直接用在 SELECT/WHERE/ORDER BY)
1. CASE WHEN(標準 SQL,功能最強)
-- 簡單 CASE
CASE col WHEN val1 THEN res1 WHEN val2 THEN res2 ELSE def END
-- 搜索 CASE
CASE WHEN cond1 THEN res1 WHEN cond2 THEN res2 ELSE def END
-- 實戰:薪資分級
SELECT name,
CASE
WHEN salary > 20000 THEN '高'
WHEN salary > 10000 THEN '中'
ELSE '低'
END AS level
FROM employee;
2. IF(expr, true_val, false_val)
SELECT IF(score >= 60, '及格', '不及格') FROM exam;
-- 巢狀 IF
SELECT IF(score >= 90, '優', IF(score >= 60, '良', '不及格')) FROM exam;
3. NULLIF / COALESCE
NULLIF(expr1, expr2) -- 相等返回 NULL,否則返回 expr1
COALESCE(v1, v2, ...) -- 返回第一個非 NULL 值
-- 實戰:電話號碼回填
SELECT COALESCE(mobile, phone, '未填寫') AS contact FROM users;
二、存儲過程/函數中的流程控制(需在 BEGIN...END 內)
1. IF...THEN...ELSEIF...ELSE...END IF
CREATE FUNCTION grade(score INT) RETURNS VARCHAR(10)
BEGIN
DECLARE g VARCHAR(10);
IF score >= 90 THEN SET g = '優';
ELSEIF score >= 80 THEN SET g = '良';
ELSEIF score >= 60 THEN SET g = '及格';
ELSE SET g = '不及格';
END IF;
RETURN g;
END;
2. WHILE 循環
CREATE PROCEDURE sum_n(IN n INT, OUT total INT)
BEGIN
DECLARE i INT DEFAULT 1;
SET total = 0;
WHILE i <= n DO
SET total = total + i;
SET i = i + 1;
END WHILE;
END;
3. REPEAT 循環(至少執行一次)
REPEAT
SET total = total + i;
SET i = i + 1;
UNTIL i > n END REPEAT;
4. LOOP + LEAVE/ITERATE(最靈活)
loop_label: LOOP
SET i = i + 1;
IF i > n THEN LEAVE loop_label; END IF;
IF MOD(i, 2) = 0 THEN ITERATE loop_label; END IF;
SET total = total + i; -- 只加奇數
END LOOP;
三、實戰場景:動態構建 WHERE 條件
-- 應用層拼接 SQL 片段(防注入用預處理)
SET @sql = CONCAT('SELECT * FROM orders WHERE 1=1');
IF @status IS NOT NULL THEN
SET @sql = CONCAT(@sql, ' AND status = ?');
END IF;
IF @start_date IS NOT NULL THEN
SET @sql = CONCAT(@sql, ' AND created_at >= ?');
END IF;
PREPARE stmt FROM @sql;
EXECUTE stmt USING @status, @start_date;
DEALLOCATE PREPARE stmt;
四、性能與兼容性提示
CASE WHEN 可被優化器改寫,性能優於多層 IF
IFNULL/COALESCE 在索引列上使用會導致索引失效,改寫為 IS NULL/IS NOT NULL 或應用層處理
- MySQL 8.0 引入
IF NOT EXISTS DDL 語法糖,簡化判斷邏輯