目錄:
一、PROCEDURE:
PROCEDURE ,事務,一個存儲過程,實際上就是在服務器端直接在數據庫中編寫一段代碼作運算,在服務器端進行高效的運算,運算結果直接返還給客戶端。
它和 FUNCTION 一個明顯的不同點是, FUNCTION 最后會有 RETURN 語句,返回運算結果, PROCEDURE 不允許有 RETURN 語句的,但是可以在參數表中指定返還數據。
PROCEDURE 編譯完成后會存儲在數據庫中,需要調用的時候使用 CALL 語句對事務或者函數進行調用。編寫 PROCEDURE 不僅可以避免重復編碼,同時還可以提高計算效率。
二、CREATE PROCEDURE基本語法:
下面不妨先看一看 CREATE PROCEDURE 以及 CREATE FUNCTION 的語法:

1 CREATE 2 [ DEFINER = { user | CURRENT_USER } ] 3 PROCEDURE sp_name ( [ proc_parameter[,... ] ]) 4 [ characteristic ... ] routine_body 5 CREATE 6 [ DEFINER = { user | CURRENT_USER } ] 7 FUNCTION sp_name ( [ func_parameter[,... ] ]) 8 RETURNS type 9 [ characteristic ... ] routine_body 10 proc_parameter: 11 [ IN | OUT | INOUT ] param_name type 12 func_parameter: 13 param_name type 14 type: 15 Any valid MySQL data type 16 characteristic: 17 COMMENT ' string ' 18 | LANGUAGE SQL 19 | [ NOT ] DETERMINISTIC 20 | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } 21 | SQL SECURITY { DEFINER | INVOKER } 22 routine_body: 23 Valid SQL routine statement
其中有幾個注意點是:
1, DEFINER 你可以用這個選項指定可以調用該 PROCEDURE 的用戶,比如說允許本地的用戶nero使用,那么可以指定為:DEFINER='nero'@'localhost',如果這個事務就是創建給當前用戶使用的,那么可以指定為:DEFINER=CURRENT_USER。
2,事務安全性:characteristic中如果使用了SQL SECURITY,那么事務每次執行的時候,指定的安全上下文都會被執行,它們會檢查當前執行這個事務的人是否擁有執行權限。
比如說下面這個小例子:
delimiter // -- 指定臨時分隔符 CREATE DEFINER = ' nero ' @ ' localhost ' PROCEDURE simpleTest(OUT outParam int , IN inParam int ) SQL SECURITY INVOKE BEGIN SELECT COUNT ( * ) INTO outParam FROM tbl WHERE col < inParam; END ; delimter ;
像上面這個例子,我們在定義的時候啟用了 “SQL SECURITY INVOKE”, 只有是:a,對這個事務有調用權限;b,對這個表tbl有select權限的用戶才能成功執行該 PROCEDURE 。
而在形參部分,則是通過 OUT 和 IN 指明參數傳入還是傳出,如果某個參數在傳入之后要作為結果傳出,那么不需要作特定指示,直接寫明參數名稱和參數類型即可。
調用這個事務則用 CALL 表達式即可:
SET @b = 100 ; CALL simpleTest( @a , @b ); SELECT @a ; -- 顯示結果
三、PROCEDURE小進階:
知道PROCEDURE的基本語法以后,學習一下編寫一個PROCEDURE經常需要用到的語句,分別有: DECLARE 聲明語句, SET 設值語句, DECLARE...HANDLER 句柄聲明語句, DECLARE...CURSOR 游標聲明語句;條件判斷 IF 和 CASE ;三種循環體: LOOP,REPEAT,WHILE 。
3.1、基本的DECLARE語句:
DECLARE基本語法:
DECLARE var_name [ , var_name ] ... type [ DEFAULT value ]
比如說在某個事務中聲明幾個臨時變量:
CREATE PROCEDURE test() BEGIN DECLARE usrID INT ; DECLARE usrName VARCHAR ( 10 ) DEFAULT ' NERO ' ; .......... -- 一些事務操作 END ;
3.2、聲明HANDLER句柄:
基本語法:

1 DECLARE handler_type HANDLER 2 FOR condition_value [ , condition_value ] ... 3 statement 4 handler_type: 5 CONTINUE 6 | EXIT 7 | UNDO 8 condition_value: 9 SQLSTATE [ VALUE ] sqlstate_value 10 | condition_name 11 | SQLWARNING 12 | NOT FOUND 13 | SQLEXCEPTION 14 | mysql_error_code
句柄的作用,就是在condition_value中,如果指定的任意條件出現了,那么statement這里的指定語句就會被執行。conditions條件有幾種類型:
1、SQLSTATE指的是當前SQL返回的狀態,這個對應的狀態就比較多了,比如狀態Error: 1169 SQLSTATE: 23000,指的是”因特定限制而導致的無法寫入的錯誤“;Error: 1162 SQLSTATE: 42000 ,指的是”結果字符串超過了最大限制“。相關的狀態代碼請自行查閱幫助文檔的” Server Error Codes and Messages “詞條。
2、SQLWARNING,但凡是SQL發出的警告信息。
3、NOT FOUND,一般來說出現在SELECT語句中,游標觸底;
4、SQLEXCEPTION,SQL錯誤。
不同的結果分別對應:
1、CONTINUE,如果條件成立,那么,在執行句柄的statement之后再繼續執行程序,比如說下面這個例子:
1 CREATE TABLE tbl(col INT , PRIMARY KEY (col)); 2 3 delimiter // 4 5 CREATE PROCEDURE HANDLER_DEMO() 6 BEGIN 7 DECLARE CONTINUE HANDLER FOR SQLSTATE ' 23000 ' SET @x2 = 1 ; 8 SET @x = 1 ; 9 INSERT INTO tbl VALUES ( 1 ); 10 SET @x = 2 ; 11 INSERT INTO tbl VALUES ( 1 ); -- 觸發句柄的statement執行 12 SET @x = 3 ; 13 END ; 14 // 15 16 CALLL HANDLER_DEMO() // 17 18 SELECT @x // 19 SELECT @x2 // 20 21 delimiter ;
結果當然是 @x為3,@x2為1 了。在代碼11行,重復插入相同的值到主鍵上觸發了23000錯誤,因而執行statement: SET @x2 = 1 ,然后再繼續執行主程序的 SET @x = 3 .
2、EXIT,一旦條件被觸發,當前BEGIN...END閉合語句將會終止執行,比如說:
1 delimiter // 2 CREATE PROCEDURE EXIT_DEMO() 3 BEGIN 4 BEGIN 5 DECLARE EXIT HANDLER FOR SQLSTATE ' 23000 ' 6 ....... 7 END ; 8 END ; 9 delimiter ;
上述代碼中,一旦出現23000錯誤,代碼行4到7的BEGIN...END閉合語句立刻終止執行。
3.3、聲明CURSOR游標 :
?聲明一個CURSOR游標:
DECLARE cursor_name CURSOR FOR select_statement
比如說最基本的:
DECLARE cur1 CURSOR FOR SELECT id,data FROM tbl;
此時cur1表示的即是SELECT語句返回的首個結果,有點類似于指針。
下面不妨看一個比較完整的例子:
1 delimiter // 2 CREATE PROCEDURE CURSOR_DEMO() 3 BEGIN 4 DECLARE done INT DEFAULT 0 ; -- INT型值,默認為0 5 DECLARE a CHAR ( 5 ); 6 DECLARE b,c INT ; 7 /* 聲明兩個游標 */ 8 DECLARE CUR1 CURSOR FOR SELECT ID,DATA FROM tbl1; 9 DECLARE CUR2 CURSOR FOR SELECT I FROM tbl2; 10 /* 聲明CONTINUE句柄,當游標觸底時被觸發 */ 11 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1 ; 12 13 /* 打開游標 */ 14 OPEN CUR1; 15 OPEN CUR2; 16 17 /* 循環插入數據,使用REPEAT...UNTIL語句 */ 18 REPEAT 19 FETCH CUR1 INTO a,b; -- 讀取游標中的數據,并移向下一行 20 FETCH CUR2 INTO c; 21 IF NOT done THEN -- 當done為0的時候條件成立 22 IF b < c THEN -- 取b和c的較小者插入表3 23 INSERT INTO tbl3 VALUES (a,b); 24 ELSE 25 INSERT INTO tbl3 VALUES (a,c); 26 END IF ; 27 END IF ; -- 當游標觸底,句柄將被觸發,done值被設為1,然后從這里繼續執行主程序 28 UNTIL done -- 句柄觸發后,done為1,執行UNTIL 29 END REPEAT; 30 31 /* 使用完畢,關閉游標 */ 32 CLOSE CUR1; 33 CLOSE CUR2; 34 END // 35 36 delimiter ;
其中,FETCH語句的基本語法如下:
FETCH cursor_name INTO var_name [ , var_name ] ...
該語句每次都會返回SELECT結果中的下一行(如果有的話)。
?3.4、循環語句:
循環涉及到的語句有:1、 LOOP、ITERATE和LEAVE ;2、 REPEAT ;3、 WHILE 。
下面直接給出對應的循環例子:
1、 LOOP、ITERATE和LEAVE:
/* LOOP,ITERATE,LEAVE */ delimiter // CREATE PROCEDURE LOOP_DEMO(param INT ) BEGIN label1: LOOP SET param = param + 1 ; IF param < 100 THEN ITERATE label1; -- 回到標簽開始處 END IF ; LEAVE label1; -- 離開標簽,退出流控制結構 END LOOP label1; -- 結束循環 END ; delimiter ;
2、REPEAT:
先給出REPEAT語法定義:
1 [ begin_label:] REPEAT 2 statement_list 3 UNTIL search_condition 4 END REPEAT [ end_label ]
可見,同樣是可以在代碼開始處插入label標簽,不過REPEAT循環是自己有控制條件的,最好能直接使用UNTIL來進行條件判斷。
比如下面這個例子:
1 delimiter // 2 CREATE PROCEDURE REPEAT_DEMO (param INT ) 3 BEGIN 4 SET @x = 0 ; 5 REPEAT 6 SET @x = @x + 1 ; 7 UNTIL @x > param 8 END REPEAT; 9 END // 10 11 delimiter ;
3、WHILE:
WHILE循環語法定義如下:
[ begin_label: ] WHILE search_condition DO statement_list END WHILE [ end_label ]
比如下面這個小例子:
delimiter // CREATE PROCEDURE WHILE_DEMO() BEGIN SET param INT DEFAULT 10 ; WHILE param < 1000 .... -- 循環內書寫具體需要處理的事務 SET param = param + 100 ; END WHILE ; END ; delimiter ;
四、順帶提一下觸發器TRIGGER:
觸發器都是和某個特定的表相關聯的,對該表設定觸發器以后,一旦對這個表進行了某個特定操作(諸如INSERT,UPDATE,DELETE),觸發器就會被觸發。
先給出CREATE TRIGGER語法定義:
CREATE [ DEFINER = { user | CURRENT_USER } ] TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_body
同樣的,可以通過DEFINER自行指定觸發器的適用對象。
在trigger_time中可以指定觸發時間(諸如:BEFORE,AFTER),trigger_event前面已經提到過了,另外,DROP TABLE或TRUNCATE TABLE這種操作是不會觸發TRIGGER的。
下面給出個小例子:
1 delimiter // 2 CREATE DEFINER ' nero ' @ ' localhost ' TRIGGER trigger_demo 3 BEFORE INSERT ON tbl1 FOR EACH ROW 4 BEGIN 5 INSERT INTO tbl2 VALUES (...........); -- INSERT操作 6 DELETE FROM tbl3 WHERE .......... ; -- 刪除操作 7 UPDATE tbl4 SET col1 = ...... ; -- 更新操作 8 END ; // 9 delimiter ;
這樣,一旦本地用戶nero對表tbl1進行INSERT操作的時候(之前,這里設置的是BEFORE),BEGIN...END內的內容就會被執行。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
