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

MySQL 存儲過程完整指南:從創建到流程控制與內建函數大全

     編輯:MySQL 綜合教學

MySQL 存儲過程完整指南:從創建到流程控制與內建函數大全

存儲過程是預編譯的 SQL 程式碼集合,儲存在資料庫中,支援參數、變量、流程控制與錯誤處理,能提升效能、減少網路傳輸、封裝業務邏輯並強化安全性。本文涵蓋 MySQL 5.0+ 存儲過程的創建、參數模式、變量作用域、條件/迴圈控制、標籤與 ITERATE、常用字串/數學/日期函數,並附完整範例。

一、基礎操作

1.1 查詢現有存儲過程

SHOW PROCEDURE STATUS;
SELECT name FROM mysql.proc WHERE db = 'your_db' AND type = 'PROCEDURE';
SELECT routine_name FROM information_schema.routines WHERE routine_schema = 'your_db';

1.2 創建、調用、刪除

DELIMITER //
CREATE PROCEDURE proc1(OUT s INT)
BEGIN
    SELECT COUNT(*) INTO s FROM user;
END //
DELIMITER ;

CALL proc1(@cnt);
SELECT @cnt;

DROP PROCEDURE proc1;

關鍵點: DELIMITER // 暫時改分隔符,避免過程內分號被誤判;結束後 DELIMITER ; 還原。使用圖形工具(如 MySQL Workbench)可免改分隔符。

二、參數模式 IN / OUT / INOUT

模式說明
IN輸入參數,調用時必須指定,過程內修改不回傳(預設)
OUT輸出參數,過程內可修改並回傳
INOUT輸入輸出,調用時指定,過程內可修改並回傳

2.1 IN 範例

DELIMITER //
CREATE PROCEDURE demo_in(IN p_in INT)
BEGIN
    SELECT p_in;
    SET p_in = 2;
    SELECT p_in;
END //
DELIMITER ;

SET @p_in = 1;
CALL demo_in(@p_in);  -- 過程內變 2,但 @p_in 仍為 1

2.2 OUT 範例

DELIMITER //
CREATE PROCEDURE demo_out(OUT p_out INT)
BEGIN
    SELECT p_out;  -- NULL
    SET p_out = 2;
    SELECT p_out;  -- 2
END //
DELIMITER ;

SET @p_out = 1;
CALL demo_out(@p_out);  -- @p_out 變為 2

2.3 INOUT 範例

DELIMITER //
CREATE PROCEDURE demo_inout(INOUT p_inout INT)
BEGIN
    SELECT p_inout;  -- 1
    SET p_inout = 2;
    SELECT p_inout;  -- 2
END //
DELIMITER ;

SET @p_inout = 1;
CALL demo_inout(@p_inout);  -- @p_inout 變為 2

三、變量與用戶變量

3.1 局部變量 DECLARE

DECLARE l_int INT UNSIGNED DEFAULT 4000000;
DECLARE l_numeric NUMERIC(8,2) DEFAULT 9.95;
DECLARE l_date DATE DEFAULT '1999-12-31';
DECLARE l_varchar VARCHAR(255) DEFAULT 'test';

3.2 賦值 SET

SET var = expr, var2 = expr2 ...;

3.3 用戶變量 @var(會話級、全域可見)

-- 客戶端使用
SELECT 'Hello' INTO @x;
SET @y = 'World';
SET @z = 1+2+3;

-- 存儲過程中使用
CREATE PROCEDURE GreetWorld()
SELECT CONCAT(@greeting, ' World');
SET @greeting = 'Hello';
CALL GreetWorld();  -- Hello World

-- 過程間傳遞
CREATE PROCEDURE p1() SET @last = 'p1';
CREATE PROCEDURE p2() SELECT CONCAT('Last: ', @last);
CALL p1(); CALL p2();  -- Last: p1

注意:濫用用戶變量會降低可讀性,優先用局部變量與參數。

四、註釋風格

  • -- 單行註釋
  • /* ... */ 多行註釋(C 風格)

五、流程控制語句

5.1 變量作用域

內層 `BEGIN ... END` 區塊可宣告同名變量遮蔽外層,離開區塊即銷毀,需透過 OUT 參數或用戶變量保留值。

5.2 條件判斷

IF-THEN-ELSE

IF var = 0 THEN
    INSERT INTO t VALUES(17);
END IF;

IF param = 0 THEN
    UPDATE t SET s1 = s1 + 1;
ELSE
    UPDATE t SET s1 = s1 + 2;
END IF;

CASE

CASE var
    WHEN 0 THEN INSERT INTO t VALUES(17);
    WHEN 1 THEN INSERT INTO t VALUES(18);
    ELSE INSERT INTO t VALUES(19);
END CASE;

5.3 迴圈

WHILE(先判斷再執行)

WHILE var < 6 DO
    INSERT INTO t VALUES(var);
    SET var = var + 1;
END WHILE;

REPEAT(先執行再判斷)

REPEAT
    INSERT INTO t VALUES(v);
    SET v = v + 1;
UNTIL v >= 5
END REPEAT;

LOOP + LEAVE(無預設條件,靠 LEAVE 跳出)

LOOP_LABEL: LOOP
    INSERT INTO t VALUES(v);
    SET v = v + 1;
    IF v >= 5 THEN LEAVE LOOP_LABEL; END IF;
END LOOP;

5.4 標籤與 ITERATE

標籤可用於 `BEGIN`、`WHILE`、`REPEAT`、`LOOP` 前,配合 `LEAVE` 跳出、`ITERATE` 重新開始該標籤區塊。

LOOP_LABEL: LOOP
    IF v = 3 THEN
        SET v = v + 1;
        ITERATE LOOP_LABEL;  -- 跳過下方 INSERT,直接下一輪
    END IF;
    INSERT INTO t VALUES(v);
    SET v = v + 1;
    IF v >= 5 THEN LEAVE LOOP_LABEL; END IF;
END LOOP;

六、常用內建函數速查

6.1 字串函數

函數說明
CONCAT(str1, str2, ...)連接字串
SUBSTRING(str, pos[, len])擷取子字串(pos 從 1 開始)
TRIM([BOTH|LEADING|TRAILING] [pad] FROM str)去除指定位置字元
REPLACE(str, from, to)替換字串
UPPER/LOWER大小寫轉換
LENGTH/CHAR_LENGTH位元組長度/字元長度
LOCATE/INSTR尋找子字串位置
LPAD/RPAD左/右填充至指定長度
LEFT/RIGHT取左/右 n 字元

注意: SUBSTRING('abcd', 0, 2) 回傳空串,SUBSTRING('abcd', 1, 2) 回傳 'ab'。

6.2 數學函數

函數說明
ABS, CEILING, FLOOR, ROUND絕對值、向上/下取整、四捨五入
MOD(n, m)取餘
POWER, SQRT冪、開根號
RAND([seed])隨機數
HEX, CONV, BIN進制轉換
LEAST, GREATEST最小/最大值
FORMAT(num, decimals)格式化數字(保留小數位)

ROUND(1.23) → 1(整數);ROUND(1.567, 2) → 1.57(浮點)。

6.3 日期時間函數

函數說明
NOW(), CURDATE(), CURTIME()當前日期時間/日期/時間
DATE_ADD/DATE_SUB(date, INTERVAL expr unit)日期加減
DATEDIFF(date1, date2)兩日期差(天)
TIMESTAMPDIFF(unit, dt1, dt2)精確差值(YEAR/MONTH/DAY/HOUR...)
DATE_FORMAT(dt, fmt)格式化輸出
STR_TO_DATE(str, fmt)字串轉日期
YEAR/MONTH/DAY/HOUR/MINUTE/SECOND提取單一欄位
LAST_DAY(date)該月最後一天
DAYOFWEEK/DAYOFYEAR/WEEK星期/年內天數/週數
MAKEDATE(year, dayofyear)年+年內天數 → 日期
MAKETIME(hour, min, sec)組合時間
SEC_TO_TIME / TIME_TO_SEC秒↔時間互轉
CONVERT_TZ(dt, from_tz, to_tz)時區轉換

七、管理與查看

  • 查看定義: SHOW CREATE PROCEDURE db.proc_name;
  • 修改: ALTER PROCEDURE proc_name ...(僅修改特性,不改邏輯)
  • 刪除: DROP PROCEDURE proc_name;

八、最佳實踐建議

  1. 業務邏輯複雜、多步驟、需原子性 → 存儲過程
  2. 參數嚴格區分 IN/OUT/INOUT,避免副作用
  3. 優先用局部變量,減少用戶變量
  4. 大量資料操作用游標 + 批次提交,避免長事務鎖死
  5. 生產環境謹慎使用動態 SQL(PREPARE/EXECUTE),防注入
  6. 版本控制存儲過程腳本,納入 CI/CD 流程

掌握存儲過程,能將資料密集型邏輯下沉到資料庫層,大幅降低應用層複雜度與網路延遲,是高效能資料庫應用的關鍵技能。

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