目錄:mysql
1、PROCEDURE;sql
PROCEDURE,事務,一個存儲過程,實際上就是在服務器端直接在數據庫中編寫一段代碼做運算,在服務器端進行高效的運算,運算結果直接返還給客戶端。spa
它和FUNCTION一個明顯的不一樣點是,FUNCTION最後會有RETURN語句,返回運算結果,PROCEDURE不容許有RETURN語句的,可是能夠在參數表中指定返還數據。
PROCEDURE編譯完成後會存儲在數據庫中,須要調用的時候使用CALL語句對事務或者函數進行調用。編寫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常常須要用到的語句,分別有:DECLARE聲明語句,SET設值語句,DECLARE...HANDLER句柄聲明語句,DECLARE...CURSOR遊標聲明語句;條件判斷IF和CASE;三種循環體:LOOP,REPEAT,WHILE。
DECLARE基本語法:
DECLARE var_name [, var_name] ... type [DEFAULT value]
好比說在某個事務中聲明幾個臨時變量:
CREATE PROCEDURE test() BEGIN DECLARE usrID INT ; DECLARE usrName VARCHAR(10) DEFAULT 'NERO'; .......... --一些事務操做 END;
基本語法:
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條件有幾種類型:
一、SQLSTATE指的是當前SQL返回的狀態,這個對應的狀態就比較多了,好比狀態Error: 1169 SQLSTATE: 23000,指的是」因特定限制而致使的沒法寫入的錯誤「;Error: 1162 SQLSTATE: 42000 ,指的是」結果字符串超過了最大限制「。相關的狀態代碼請自行查閱幫助文檔的」Server Error Codes and Messages「詞條。
二、SQLWARNING,但凡是SQL發出的警告信息。
三、NOT FOUND,通常來講出如今SELECT語句中,遊標觸底;
四、SQLEXCEPTION,SQL錯誤。
不一樣的結果分別對應:
一、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.
二、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閉合語句馬上終止執行。
聲明一個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結果中的下一行(若是有的話)。
循環涉及到的語句有:一、LOOP、ITERATE和LEAVE;二、REPEAT;三、WHILE。
下面直接給出對應的循環例子:
/*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 ;
先給出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 ;
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 ;
觸發器都是和某個特定的表相關聯的,對該表設定觸發器之後,一旦對這個表進行了某個特定操做(諸如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內的內容就會被執行。