核心概念:變量類型與作用域
| 類型 | 語法 | 作用域 | 命名規則 | 典型用途 |
| 局部變量 | DECLARE var_name type [DEFAULT val] | BEGIN...END 區塊內 | 不帶 @,如 v_count | 存儲過程/函數/觸發器內部邏輯 |
| 用戶變量 | SET @var_name = expr | 會話級 (連線存活期) | 帶 @,如 @total | 跨存儲過程傳值、客戶端交互 |
| 系統變量 | SET GLOBAL/SESSION var = val | 全域/會話 | @@var_name | 配置參數調整 |
| 參數 | IN/OUT/INOUT param_name type | 存儲過程調用期間 | 不帶 @ | 輸入/輸出/雙向傳參 |
一、局部變量:DECLARE 定義與賦值
1. 定義規則
| 方式 | 語法 | 特點 |
| SET | SET var = expr [, var = expr] ... | 通用、可賦值給用戶變量 (@var)、可定義新用戶變量 |
| SELECT ... INTO | SELECT col INTO var FROM tbl WHERE ... | 查詢結果直接賦值、必須返回單行、可賦值給 OUT 參數 |
| DEFAULT 子句 | DECLARE var type DEFAULT val | 定義時初始化 |
3. 實戰範例:查詢部門人數
| 條件值類型 | 語法 | 例子 | 涵蓋範圍 |
| MySQL 錯誤碼 | mysql_error_code | 1062 (主鍵重複)、1048 (非空違反) | 具體單一錯誤 |
| SQLSTATE | SQLSTATE 'value' | '23000' (完整性約束違反) | 一類錯誤 (ANSI 標準) |
| 條件名稱 | condition_name | 自定義 DECLARE dup_key CONDITION FOR 1062 | 可讀性、復用 |
| SQLWARNING | SQLWARNING | | 所有 01 開頭 SQLSTATE |
| NOT FOUND | NOT FOUND | | 所有 02 開頭 (游標無數據) |
| SQLEXCEPTION | SQLEXCEPTION | | 除上述外所有錯誤 |
2. 處理器類型:CONTINUE vs EXIT vs UNDO
| 類型 | 行為 | 適用場景 |
| CONTINUE | 執行處理語句後,繼續執行後續 SQL | 記錄錯誤、設標誌、嘗試修復、批量處理容錯 |
| EXIT | 執行處理語句後,立即退出當前 BEGIN...END 區塊 | 嚴重錯誤不可恢復、事務回滾觸發 |
| UNDO | MySQL 尚未實現 | 保留關鍵字 |
3. 完整實戰:主鍵重複時記錄標誌並繼續/退出
場景 A:CONTINUE - 批量導入容錯
CREATE PROCEDURE CriticalTransfer()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SELECT 'Critical error, rolled back' AS result;
END;
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- 若失敗 (如 id=2 不存在)
COMMIT;
SELECT 'Transfer succeeded' AS result;
END
4. 進階:自定義條件名稱提升可讀性
CREATE PROCEDURE SafeTransfer(IN from_id INT, IN to_id INT, IN amount DECIMAL(10,2))
BEGIN
DECLARE v_error INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_error = 1;
START TRANSACTION;
UPDATE accounts SET balance = balance - amount WHERE id = from_id AND balance >= amount;
UPDATE accounts SET balance = balance + amount WHERE id = to_id;
IF v_error = 1 OR ROW_COUNT() = 0 THEN
ROLLBACK;
SELECT 'Transfer failed' AS result;
ELSE
COMMIT;
SELECT 'Transfer succeeded' AS result;
END IF;
END
四、最佳實踐總結
- 變量命名規範: 局部
v_、參數 p_、用戶 @、系統 @@
- DECLARE 置頂: 所有局部變量/條件/處理器必須在
BEGIN 後、第一條 SQL 前
- SELECT INTO 單行鐵律: 返回 0 行 → 變量保持原值/NULL;返回 >1 行 → 報錯 1172。必須加
LIMIT 1 或確保唯一
- 處理器精準匹配: 優先用具體錯誤碼 (1062) > SQLSTATE ('23000') > SQLEXCEPTION,避免誤捕
- CONTINUE 用於批量/容錯,EXIT 用於關鍵事務
- 事務邊界清晰: START TRANSACTION 必須在所有 DECLARE 之後
- 測試驗證: 故意製造錯誤 (重複鍵、FK 違反、死鎖) 驗證處理器行為
總結
MySQL 存儲過程變量與條件處理是構建健壯、可維護資料庫邏輯的基石。掌握 DECLARE/SET/SELECT INTO 三種賦值差異、CONTINUE/EXIT 處理器語義、精準錯誤碼匹配與事務邊界控制,即可編寫生產級存儲過程。下一篇將深入游標、循環、動態 SQL 進階技巧。