存儲過程(Stored Procedure)是在大型數據庫系統中,一組爲了完成特定功能的SQL 語句集,它存儲在數據庫中,一次編譯後永久有效,用戶經過指定存儲過程的名字並給出參數(若是該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象。mysql
語法:sql
CREATE PROCEDURE 存儲過程名( IN|OUT|INOUT 參數名 數據類型 , ...) BEGIN ... END;
MySQL存儲過程的參數類型:數據庫
IN,表示存儲過程的輸入參數,該參數的值將會傳遞給存儲過程,在存儲過程當中能夠對該參數進行修改,可是在存儲過程返回時,該參數值不會被返回,至關於在存儲過程當中對該參數的修改對調用者來講是不可見的。oop
OUT,表示存儲過程的輸入參數,該參數的值會在存儲過程當中初始化爲NULL,當存儲過程返回時,該值也會被返回,調用者能夠看到被修改後的值。fetch
INOUT,表示存儲過程的輸入輸出參數,該參數由調用者初始化,在存儲過程當中的作的任何更改都會被返回,調用者能夠看到修改後的值。命令行
存儲過程建立示例:code
建立存儲過程student_procedure,student_procedure有一個輸入參數age和一個輸出參數num,查詢tb_student表學生年齡大於等於輸入參數age的人數,並將人數設置到num。對象
CREATE PROCEDURE student_procedure(IN age TINYINT, OUT num INT) BEGIN SELECT COUNT(*) INTO num FROM tb_student t WHERE t.age>=age; END;
MySQL命令行建立存儲過程:內存
若是是在MySQL命令行建立存儲過程,則須要臨時的修改語句分隔符,由於MySQL默認語句分隔符是;,會使存儲過程當中的語句被直接解析而致使語法錯誤。ci
-- 設置//爲語句分隔符 mysql> DELIMITER // mysql> CREATE PROCEDURE student_procedure(IN age TINYINT, OUT num INT) -> BEGIN -> SELECT COUNT(*) INTO num FROM tb_student t WHERE t.age>=age; -> END; -> // Query OK, 0 rows affected --恢復爲原來的分隔符 mysql> DELIMITER ;
tb_student表數據:
+----+------+-----+-------------+-----------+----------+ | id | name | age | phone | address | class_id | +----+------+-----+-------------+-----------+----------+ | 1 | 小明 | 18 | 188xxxx1234 | xxxxxxxxx | 1 | | 2 | 小米 | 28 | 188xxxx1234 | xxxxxxxxx | 2 | | 3 | 小看 | 28 | 188xxxx1234 | xxxxxxxxx | 3 | | 4 | 小阿 | 38 | 188xxxx1234 | xxxxxxxxx | 3 | | 5 | 小鬼 | 48 | 188xxxx1234 | xxxxxxxxx | 3 | +----+------+-----+-------------+-----------+----------+
調用存儲過程,查詢年齡大於38的學生人數:
-- 調用存儲過程 mysql> CALL student_procedure(38, @num); Query OK, 1 row affected -- 查看返回結果 mysql> select @num; +------+ | @num | +------+ | 2 | +------+
語法:
SHOW CREATE PROCEDURE proc_name;
如查看student_procedure的定義:
mysql> SHOW CREATE PROCEDURE student_procedure; +-------------------+----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+ | Procedure | sql_mode | Create Procedure | character_set_client | collation_connection | Database Collation | +-------------------+----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+ | student_procedure | STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | CREATE DEFINER=`root`@`localhost` PROCEDURE `student_procedure`(IN age TINYINT, OUT num INT) BEGIN SELECT COUNT(*) INTO num FROM tb_student t WHERE t.age>=age;END | utf8 | utf8_general_ci | utf8_general_ci | +-------------------+----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
語法:
ALTER PROCEDURE proc_name [characteristic ...] characteristic: { COMMENT 'string' | LANGUAGE SQL | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } }
ALTER PROCEDURE 語句用於修改存儲過程的某些特徵。若是要修改存儲過程的內容,能夠先刪除原存儲過程,再以相同的命名建立新的存儲過程。
語法:
DROP PROCEDURE [ IF EXISTS ] proc_name
如刪除student_procedure:
mysql> DROP PROCEDURE student_procedure; Query OK, 0 rows affected mysql> CALL student_procedure(38, @num); 1305 - PROCEDURE student_procedure does not exist
語法:
IF 判斷條件 THEN 處理語句 [ELSEIF 判斷條件 THEN 處理語句]... [ELSE 處理語句] END IF
示例:
CREATE PROCEDURE test1(IN sex TINYINT) BEGIN IF sex=1 THEN SET @sex='男'; ELSEIF sex=0 THEN SET @sex='女'; ELSE SET @sex='未知'; END IF; END;
CASE語句有兩種寫法:
語法1:
CASE 值 WHEN 值1 THEN 處理語句 [WHEN 值2 THEN 處理語句]... [ELSE 處理語句] END CASE
語法2:
CASE WHEN 條件判斷 THEN 處理語句 [WHEN 條件判斷 THEN 處理語句] ... [ELSE 處理語句] END CASE
示例:
-- 寫法1 CREATE PROCEDURE test2(IN sex TINYINT) BEGIN CASE sex WHEN 1 THEN SET @sex='男'; WHEN 0 THEN SET @sex='女'; ELSE SET @sex='未知'; END CASE; END; -- 寫法2 CREATE PROCEDURE test3(IN sex TINYINT) BEGIN CASE WHEN sex=1 THEN SET @sex='男'; WHEN sex=0 THEN SET @sex='女'; ELSE SET @sex='未知'; END CASE; END;
LOOP循環是一個死循環,通常狀況須要配合LEAVE語句和ITERATE語句使用,LEAVE語句表示跳出該循環(相似Java中的break),ITERATE語句表示跳出本次循環(相似Java中的continue)。
語法:
[別名:]LOOP 處理邏輯 END LOOP [別名]
示例:
CREATE PROCEDURE test4() BEGIN SET @num=0; add_num:LOOP SET @num=@num+1; IF @num=10 THEN LEAVE add_num; END IF; END LOOP add_num; END;
REPEAT語句是自帶條件判斷的循環語句,每次語句執行完畢後,會對條件進行判斷,若是爲true則退出循環,不然繼續循環。(相似Java中的do while循環)
語法:
[別名:] REPEAT 處理語句 UNTIL 條件判斷 END REPEAT [別名]
示例:
CREATE PROCEDURE test5() BEGIN SET @num=0; add_num:REPEAT SET @num=@num+1; UNTIL @num=10 END REPEAT add_num; END;
WHILE語句也是自帶條件判斷的循環,和REPEAT語句的區別在於WHILE語句會先進行條件判斷,當條件判斷爲true時才繼續執行循環中的語句,爲false則直接退出循環。(相似於Java中的while循環)
語法:
[別名:] WHILE 條件判斷 DO 處理邏輯 END WHILE [別名]
示例:
CREATE PROCEDURE test6() BEGIN SET @num=0; add_num:WHILE @num<10 DO SET @num=@num+1; END WHILE add_num; END;
遊標是用來逐行處理某個查詢的結果集。
遊標的聲明必須出如今HANDLER聲明以前聲明,變量和條件聲明以後聲明。
DECLARE 遊標名稱 CURSOR FOR sql查詢;
OPEN 遊標名稱;
FETCH 遊標名稱 INTO 變量1 [,變量2]...
將結果集中的數據保存到對應的變量當中去,遊標第一次使用時默認讀取結果集中的第一行,通常配合循環語句逐行處理整個結果集。
CLOSE 遊標名稱;
CLOSE釋放遊標使用的全部內部內存和資源,所以每一個遊標再也不須要時都應該關閉。遊標關閉後不能使用,若是須要使用則須要從新打開遊標。
查詢tb_student表,將全部學生名稱鏈接成一個字符串設置到變量@name_Str中。
CREATE PROCEDURE test7() BEGIN -- 聲明局部變量student_name,用於接收數據集中的數據 DECLARE student_name VARCHAR(10); -- 聲明局部變量done,用於判斷是否退出循環,默認值爲FALSE DECLARE done INT DEFAULT FALSE; -- 聲明遊標my_cursor DECLARE my_cursor CURSOR FOR SELECT `name` FROM tb_student; -- 聲明continue handler句柄,當出現SQLSTATE '02000'時將done設置爲TRUE DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = TRUE; -- 設置用戶變量@name_Str爲空字符串 SET @name_Str=''; -- 打開遊標 OPEN my_cursor; -- 開始LOOP循環 concat_name:LOOP -- 將數據集中的一行數據存放到指定的變量中 FETCH my_cursor INTO student_name; -- 判斷是否退出循環 IF done THEN LEAVE concat_name; END IF; -- 鏈接學生名稱字符串 SET @name_Str = CONCAT(@name_Str,student_name); END LOOP concat_name; -- 關閉遊標 CLOSE my_cursor; END;
結果:
mysql> call test7(); Query OK, 0 rows affected mysql> select @name_Str; +----------------------+ | @name_Str | +----------------------+ | 小明小米小看小阿小鬼 | +----------------------+
在使用遊標時,能夠經過FETCH將數據集中的數據保存到變量中進行處理,可是當整個數據集已經FETCH結束的時候,再去FETCH就會拋異常:
1329 - No data - zero rows fetched, selected, or processed
該異常對應的SQLSTATE爲02000,因此須要指定句柄捕獲這種異常狀況來給標誌賦值,後續就能夠經過這個標誌來判斷數據集循環讀取結束。
異常信息詳見:Error Reference