MySQL 5.0 引入預存程序,支援變量宣告、條件判斷、循環控制,讓資料庫層能處理複雜業務邏輯。本講系統梳理核心語法與實戰模式。
DECLARE 語法DECLARE var_name [, var_name] ... type [DEFAULT value];
BEGIN ... END 複合語句區塊中使用@ 前綴),型別必須顯式宣告DEFAULT 時初始值為 NULLSET var = expr 賦值-- 風格 1:分行宣告 + 後設值
DECLARE a INT;
DECLARE b INT;
SET a = 5; SET b = 5;
-- 風格 2:合併宣告 + DEFAULT
DECLARE a, b INT DEFAULT 5;
-- 風格 3:混合 (不推薦,降低可讀性)
DECLARE a INT DEFAULT 5;
DECLARE b INT;
SET b = 5;
建議:風格 2 最簡潔,風格 1 適合複雜初始化邏輯。
CREATE PROCEDURE p_scope()
BEGIN
DECLARE x1 CHAR(5) DEFAULT 'outer';
BEGIN
DECLARE x1 CHAR(5) DEFAULT 'inner';
SELECT x1; -- 'inner' (內層遮蔽外層)
END;
SELECT x1; -- 'outer' (內層變量已銷毀)
END;
BEGIN ... END 形成新作用域END 時內層變量銷毀OUT 參數或賦值給會話變量 (@var)IF 與 CASEIF ... THEN ... ELSE ... END IFCREATE PROCEDURE p_if(IN param1 INT)
BEGIN
DECLARE var1 INT;
SET var1 = param1 + 1;
IF var1 = 0 THEN
INSERT INTO t VALUES (17);
END IF;
IF param1 = 0 THEN
UPDATE t SET s1 = s1 + 1;
ELSE
UPDATE t SET s1 = s1 + 2;
END IF;
END;
執行流程追蹤 (呼叫 p_if(0)):
var1 = 1 → 第一個 IF 條件假 → 跳過param1 = 0 → 第二個 IF 條件真 → 執行 s1 = s1 + 1CASE ... WHEN ... THEN ... ELSE ... END CASECREATE PROCEDURE p_case(IN param1 INT)
BEGIN
DECLARE var1 INT;
SET var1 = param1 + 1;
CASE var1
WHEN 0 THEN INSERT INTO t VALUES (17);
WHEN 1 THEN INSERT INTO t VALUES (18);
ELSE INSERT INTO t VALUES (19);
END CASE;
END;
CASE 適合「單一運算式對多值」分支,比多重 IF 更清晰NULL 值不匹配任何 WHEN,走 ELSE 分支CALL p_case(NULL) 結果?var1 = NULL + 1 = NULL → 無 WHEN 匹配 → 執行 ELSE → 插入 19。實測確認表新增一行值為 19。
WHILE ... END WHILE (前測試)CREATE PROCEDURE p_while()
BEGIN
DECLARE v INT DEFAULT 0;
WHILE v < 5 DO
INSERT INTO t VALUES (v);
SET v = v + 1;
END WHILE;
END;
NULL 參與運算導致無限循環REPEAT ... UNTIL ... END REPEAT (後測試)CREATE PROCEDURE p_repeat()
BEGIN
DECLARE v INT DEFAULT 0;
REPEAT
INSERT INTO t VALUES (v);
SET v = v + 1;
UNTIL v >= 5
END REPEAT;
END;
UNTIL 後**無分號** (可加但非標準)DO ... WHILELOOP ... END LOOP (無內建條件,配合 LEAVE)CREATE PROCEDURE p_loop()
BEGIN
DECLARE v INT DEFAULT 0;
loop_label: LOOP
INSERT INTO t VALUES (v);
SET v = v + 1;
IF v >= 5 THEN
LEAVE loop_label;
END IF;
END LOOP;
END;
label_name: 前綴,LEAVE label_name 跳出BEGIN/WHILE/REPEAT/LOOP 前GOTO (非標準、不推薦、未來將移除)CREATE PROCEDURE p_goto()
BEGIN
DECLARE v INT DEFAULT 0;
my_label: LOOP
IF v = 3 THEN
GOTO my_label; -- 死循環示範
END IF;
SET v = v + 1;
END LOOP;
END;
警告:破壞結構化程式設計,難以維護,僅為相容性保留,**嚴禁生產代碼使用**。
ITERATE (相當於 continue)CREATE PROCEDURE p_iterate()
BEGIN
DECLARE v INT DEFAULT 0;
loop_label: LOOP
IF v = 3 THEN
SET v = v + 1;
ITERATE loop_label; -- 跳過本輪剩餘,直接下一輪
END IF;
INSERT INTO t VALUES (v);
SET v = v + 1;
IF v >= 5 THEN
LEAVE loop_label;
END IF;
END LOOP;
END;
執行追蹤:
IF 真 → v=4 → ITERATE → **跳過插入 3**、直接下一輪LEAVE 結束label_name: 置於 BEGIN/WHILE/REPEAT/LOOP **前**END WHILE label_name、END REPEAT label_name、END LOOP label_name、END label_name — 必須與開始標籤同名,建議加上提升可讀性LEAVE label:跳出指定標籤區塊ITERATE label:重新開始指定標籤迴圈CREATE PROCEDURE p_all(IN p1 INT, OUT p2 INT)
LANGUAGE SQL
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
DECLARE v INT;
DECLARE goto_label LABEL; -- 標籤宣告 (GOTO 用)
start_label: LOOP
IF v = v THEN LEAVE start_label; ELSE ITERATE start_label; END IF;
END LOOP start_label;
REPEAT
WHILE 1 = 0 DO BEGIN END; END WHILE;
UNTIL v = v END REPEAT;
GOTO goto_label;
END;
包含:參數模式 (IN/OUT/INOUT)、特性子句 (LANGUAGE/DETERMINISTIC/SQL SECURITY)、變量宣告、標籤、IF/WHILE/LOOP/REPEAT/LEAVE/ITERATE/GOTO — **語法合法但邏輯無意義**,展示語法完整性。
| 場景 | 推薦構造 | 避免 |
|---|---|---|
| 已知迴圈次數/條件前檢查 | WHILE | LOOP+LEAVE |
| 至少執行一次/條件後檢查 | REPEAT | WHILE 需額外旗標 |
| 複雜中斷/多層巢狀 | LOOP + 標籤 + LEAVE/ITERATE | GOTO |
| 單值多分支 | CASE | 多重 IF |
| 布林條件分支 | IF | CASE (需轉換) |
DETERMINISTIC、READS SQL DATA/MODIFIES SQL DATA 正確宣告特性,助優化器決策游標 (CURSOR)、條件處理 (DECLARE ... HANDLER)、動態 SQL (PREPARE/EXECUTE)、觸發器與事件排程器 — 解鎖預存程序完整威力。