| 類別 | 語句 | 使用範圍 | 返回值 |
|---|---|---|---|
| 條件判斷 | IF ... THEN ... ELSEIF ... ELSE ... END IF | 儲存過程/函數/觸發器/事件 | 無 (語句) |
| 條件表達式 | IF(condition, true_val, false_val) | **任何 SQL 位置** (SELECT、WHERE、SET) | 有 (表達式) |
| 多分支 | CASE WHEN ... THEN ... ELSE ... END CASE | 儲存過程/函數/觸發器/事件 | 無 (語句) |
| 簡單 CASE | CASE expr WHEN val THEN ... END CASE | 同上 | 無 |
| 迴圈 | WHILE / REPEAT / LOOP | 同上 | 無 |
-- IF 函數 (表達式,可用於 SELECT)
SELECT IF(score >= 60, 'Pass', 'Fail') AS result FROM exams;
-- IF 語句 (流程控制,僅程式區塊)
CREATE FUNCTION grade(score INT) RETURNS VARCHAR(10)
BEGIN
DECLARE result VARCHAR(10);
IF score >= 85 THEN SET result = 'Excellent';
ELSEIF score >= 60 THEN SET result = 'Pass';
ELSE SET result = 'Fail';
END IF;
RETURN result;
END;
CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
WHEN score >= 70 THEN 'C'
ELSE 'D'
END CASE;
CASE day_of_week
WHEN 1 THEN 'Mon'
WHEN 2 THEN 'Tue'
...
ELSE 'Invalid'
END CASE;
DELIMITER //
CREATE FUNCTION `round_to_dozen`(qty INT) RETURNS INT
DETERMINISTIC
BEGIN
WHILE qty % 12 > 0 DO
SET qty = qty + 1;
END WHILE;
RETURN qty;
END//
DELIMITER ;
SELECT round_to_dozen(10); -- 12
SELECT round_to_dozen(24); -- 24
SELECT round_to_dozen(25); -- 36
DELIMITER $$
CREATE PROCEDURE `print_odd_while`()
BEGIN
DECLARE i INT DEFAULT 1;
loop_label: WHILE i <= 10 DO
IF (i % 2) <> 0 THEN
SELECT CONCAT(i, ' is odd');
END IF;
SET i = i + 1;
END WHILE loop_label;
END$$
DELIMITER ;
CALL print_odd_while();
CREATE PROCEDURE `dynamic_query`(IN tbl_name VARCHAR(64), IN filter_json JSON)
BEGIN
DECLARE sql_text TEXT DEFAULT 'SELECT * FROM ';
DECLARE where_clause TEXT DEFAULT '';
SET sql_text = CONCAT(sql_text, '`', tbl_name, '`');
IF JSON_CONTAINS_PATH(filter_json, 'one', '$.status') THEN
SET where_clause = CONCAT(where_clause, ' AND `status` = ', JSON_UNQUOTE(JSON_EXTRACT(filter_json, '$.status')));
END IF;
IF JSON_CONTAINS_PATH(filter_json, 'one', '$.date_from') THEN
SET where_clause = CONCAT(where_clause, ' AND `created_at` >= ', JSON_UNQUOTE(JSON_EXTRACT(filter_json, '$.date_from')));
END IF;
IF where_clause <> '' THEN
SET sql_text = CONCAT(sql_text, ' WHERE ', SUBSTRING(where_clause, 5)); -- 移除前導 ' AND '
END IF;
SET @stmt = sql_text;
PREPARE stmt FROM @stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;
QUOTE() 或參數綁定 (PREPARE ... USING),嚴禁直接拼接。DETERMINISTIC 允許查詢緩存/複製優化。max_sp_recursion_depth (預設 0 禁用),啟用後小心棧溢位。MySQL 流程控制核心在於**區分「語句」與「表達式」**:**IF/CASE/WHILE/LOOP** 是語句,僅能在 `BEGIN ... END` 程式區塊使用;**IF()/CASE 表達式** 可內嵌於任何 SQL。掌握這一界限,才能在正確位置使用正確工具,寫出安全、高效、可維護的儲存邏輯。