1、創建存儲過程和函數
存儲過程是一條或者多條SQL語句的集合,相當於批處理文件,但是作用不僅僅限於批處理。使用存儲過程將簡化操作,減少冗餘的步驟,同時還可減少操作過程的失誤,提高效率。
(1)創建存儲過程
創建存儲過程是通過”CREATE PROCEDURE”語句來創建,語法格式爲:
CREATE PROCEDURE sp_name ([proc_parameter])
[characteristics…] routine_body
各選項說明:
CREATE PROCEDURE:創件存儲過程的關鍵字
sp_name:存儲過程名稱
proc_parameter:指定存儲過程的參數列表,列表形式爲:[ IN | OUT | INOUT ] param_name type
characteristics:用於指定存儲過程的特性
routine_body:mysql sql語句內容,使用BEGINE…END來表示SQL代碼的開始和結束。
# 創建存儲過程前先將sql語句結束符改爲//,以防止和默認的結束符衝突,
mysql> delimiter //
mysql> create procedure proc()
-> begin
-> select * from course;
-> end //
Query OK, 0 rows affected (0.08 sec)
# 存儲過程創建完成後將結束符改爲默認的結束符
mysql> delimiter ;
# 調用創建的存儲過程
mysql> call proc();
+----+-------------+------------+
| id | course_name | teacher_id |
+----+-------------+------------+
| 1 | math | 3 |
| 2 | english | 2 |
(2)創建存儲函數
函數與存儲過程最大的區別就是函數調用有返回值,調用存儲過程用call語句,而調用函數就直接引用函數名+參數即可,創建存儲函數使用”CREATE FUNCTION”語句來創建,語法格式爲:
CREATE FUNCTION func_name ( param_name type )
RESTURNS type
[characteristic……] routine_body
主要參數說明:
Param_name:參數名稱
Type:參數類型
RETURNS type:函數返回數據的類型
Characteristic:指定存儲函數的特性
mysql> delimiter //
# 創建一個函數
mysql> create function stubak_update(param1 int)
-> returns int
-> begin
-> update student_bak set gender=1 where sid=param1;
-> select count(*) into @a from student_bak where sid>param1;
-> return @a;
-> end;
-> //
mysql> delimiter ;
# 調用函數,並傳入一個參數
mysql> select stubak_update(1);
+------------------+
| stubak_update(1) |
+------------------+
| 7 |
+------------------+
2、存儲過程中使用變量
(1)定義變量
在存儲過程中通過DECLARE語句定義變量,定義變量的格式如下:
DECLARE var_name[,varname]… date_type [DEFAULT value];
選項說明:
var_name:局部變量名稱
DEFAULT value:用於給變量提供一個默認值
Type:用於指定變量的默認類型
(2)爲變量賦值
聲明後的變量可以通過select … into var_list進行賦值,或者通過set語句賦值,或者通過定義遊標並使用fetch … into var_list賦值,使用set賦值的方式如下:
SET var_name = expr [, var_name = expr] ……;
# mysql存儲過程中使用變量
mysql> delimiter //
mysql> create procedure sp1(v_sid int)
-> begin
-> declare xname varchar(10) default 'dayi123';
-> declare xsex int;
-> select sname,gender into xname,xsex from student_bak where sid=v_sid;
-> select xname,xsex;
-> end;
-> //
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;
mysql> call sp1(1);
+--------+------+
| xname | xsex |
+--------+------+
| Andrew | 1 |
+--------+------+
3、定義條件和處理程序
定義條件是事先定義程序執行過程中遇到的問題,處理程序定義了在遇到這些問題是應當採取的處理方式,並且保證存儲過程或函數在遇到警告或錯誤時能繼續執行。
(1)定義條件
定義條件使用DECLARE語句,語法格式如下
DECLARE condition_name CONDITION FOR [condition_type]
[condition_type]:
SQLSTATE [VALUE] sqlstate_value | mysql_error_code
各選項說明:
Condition_name:表示條件名稱
Condition_type:表示條件類型
sqlstate_value | mysql_error_code:mysql中的錯誤,sqlstate_value爲長度爲5的字符串類型錯誤代碼,mysql_error_code爲數值類型的錯誤代碼
(2)定義處理程序
定義處理程序時,使用DECLARE語句實現:
DECLARE handler_type HANDLER FOR condition_value[,…] sp_statement handler_type:
CONTINUT | EXIT | UNDO
Condition_value:
SQLSTATE [VALUE] sqlstate_value | condition_name
| SQLWARNING | NOT FOUND | SQLEXCEPTION | mysql_error_code
各選項說明:
Handler_type:錯誤處理方式,continue表示遇到錯誤不處理,exit爲退出,undo爲撤回之前操作。
Condition_value表示錯誤類型,有以下的取值
SQLSTATE [VALUE] sqlstate_value:包含5個字符的字符串錯誤值
condition_name:declare condition定義錯誤的錯誤條件名稱
SQLWARNING:匹配所有以01開頭SQLSTATE錯誤代碼
NOT FOUND:匹配所有以02開頭的SQLSTATE錯誤代碼
SQLEXCEPTION:匹配所有沒有被SQLWARENING或NOT FOUNT捕獲的SQLSTATE的錯誤代碼
mysql_error_code:匹配數值類型的錯誤代碼
sp_statement:在遇到定義的錯誤時,需要執行的存儲過程或函數。
當condition發生但沒有聲明handler時,則存儲過程和函數依照如下規則處理:
發生SQLEXCEPTION錯誤,則執行exit退出
發生SQLWARNING警告,則執行contine繼續執行
發生NOT FOUND情況,則執行continue繼續執行
# 創建一個存儲過程並定義處理程序當錯誤嗎爲23000時跳過繼續執行
# 創建一張用於測試的表
mysql> delimiter //
mysql> create procedure handlerdemo()
-> begin
-> declare continue handler for sqlstate '23000' set @x2=1;
-> set @x=1;
-> insert into t values(1);
-> set @x=2;
-> insert into t values(1);
-> set @x=3;
-> end;
-> //
mysql> delimiter ;
# 調用存儲過程
mysql> CALL handlerdemo();
# 插看變量的值
mysql> select @x;
+------+
| @x |
+------+
| 3 |
+------+
4、存儲過程中的流程控制語句
MySQL支持if,case,iterate,leave,loop,while,repeat語句作爲存儲過程和函數中的流程控制語句,另外return語句也是函數中的特定流程控制語句。
(1)case語句
Case語句有兩種語句格式分別如下:
格式一:
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list]……
[ELSE statement_list]
END CASE
格式二:
CASH
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list]……
[ELSE statement_list]
END CASE
創建存儲過程時使用case語句
mysql> delimiter //
mysql> CREATE PROCEDURE exp_case(v_sid int)
-> BEGIN
-> DECLARE v INT DEFAULT 1;
-> select gender into v from student_bak where sid=v_sid;
-> CASE
-> WHEN v=0 THEN update student_bak set gender=1 where sid=v_sid;
-> WHEN v=1 THEN update student_bak set gender=0 where sid=v_sid;
-> ELSE
-> update student_bak set gender=-1 where sid=v_sid;
-> END CASE;
-> END;
-> //
mysql> delimiter ;
(2)if語句
If語句包含多個條件判斷,根據條件判斷的結果爲TRUE或FALSE執行相應的語句,語法格式爲:
IF search_condition THEN statement_List
[ELSEIF search_condition THEN statement_list] …
[ELSE statement_list]
END IF
創建一個函數,使用if語句判斷兩個數的大小
mysql> CREATE FUNCTION exp_if(n INT, m INT)
-> RETURNS VARCHAR(20)
-> BEGIN
-> DECLARE s VARCHAR(20);
-> IF n > m THEN SET s = '>';
-> ELSEIF n = m THEN SET s = '=';
-> ELSE SET s = '<';
-> END IF;
-> SET s = CONCAT(n, ' ', s, ' ', m);
-> RETURN s;
-> END //
mysql> DELIMITER ;
mysql> select exp_if(1,2);
+-------------+
| exp_if(1,2) |
+-------------+
| 1 < 2 |
+-------------+
If語句也可在創建存儲過程及函數時嵌套使用,
mysql> CREATE FUNCTION exp_if02 (n INT, m INT)
-> RETURNS VARCHAR(50)
-> BEGIN
-> DECLARE s VARCHAR(50);
-> IF n = m THEN SET s = 'equals';
-> ELSE
-> IF n > m THEN SET s = 'greater';
-> ELSE SET s = 'less';
-> END IF;
-> SET s = CONCAT('is ', s, ' than');
-> END IF;
-> SET s = CONCAT(n, ' ', s, ' ', m, '.');
-> RETURN s;
-> END //
mysql> delimiter ;
(3)iterate語句
Iterate語句僅出現在loop,repeat,while循環語句中,其含義表示重新開始此循環,格式如下:
ITERATE label
Label表示自定義的標籤名
(4)leave語句
Leave語句表明退出指定標籤的流程控制語句塊,通常會用在begin…end,以及loop,repeat,while的循環語句中,格式如下:
LEAVE label
Label表示要退出的標籤名
(5)LOOP語句
Loop語句是存儲過程或函數中表達循環執行的一種方式,LOOP內的語句一直重複執行直到循環被退出,跳出循環時使用LEVAVE子句,LOOP語句的基本格式如下:
[begin_label:] LOOP
Statement_list
END LOOP [ END_LABEL ]
創建存儲過程使用loop循環語句實現變量的自增
mysql> DELIMITER //
# 創建存儲過程
mysql> CREATE PROCEDURE exp_loop(p1 INT)
-> BEGIN
-> label1: LOOP
-> SET p1 = p1 + 1;
-> IF p1 < 10 THEN
-> ITERATE label1;
-> END IF;
-> LEAVE label1;
-> END LOOP label1;
-> SET @x = p1;
-> END //
mysql> DELIMITER ;
# 調用存儲過程
mysql> call exp_loop(1);
# 查看執行後變量的值
mysql> select @x;
+------+
| @x |
+------+
| 10 |
+------+
(6)repeat語句
Repeat語句用於創建一個帶條件判斷的循環過程,每次語句執行完畢之後,會對條件表達式進行判斷,如果表達式爲真,則循環結束;否則重複執行循環中的語句。
[repeat_label:] REPEAT
Statement_List
UNTIL search_condition
END REPEAT [repeat_label]
Repeat_label爲REPEAT語句的標註名稱,該參數可省略
mysql> delimiter //
# 創建基於repeat循環的存儲過程
mysql> CREATE PROCEDURE exp_rep(p1 INT)
-> BEGIN
-> SET @x = 0;
-> REPEAT
-> SET @x = @x + 1;
-> UNTIL @x > p1 END REPEAT;
-> END
-> //
mysql> delimiter ;
# 調用存儲過程,並查看變量@x的最終值
mysql> call exp_rep(100);
mysql> select @x;
+------+
| @x |
+------+
| 101 |
+------+
(7)while語句
While語句也是用於創建一個帶條件判斷的存儲過程,與REPEAT不同的是while在執行語句時先對指定的表達式進行判斷,如果爲真,則執行循環內的語句,否則退出,語句格式如下:
[while_label:] WHILE expr_condition DO
Statement_list
END WHILE [while_label]
創建基於while循環的存儲過程,相對於repeat循環是先判斷在執行。
mysql> DELIMITER //
mysql> CREATE PROCEDURE exp_whi(p1 INT)
-> BEGIN
-> SET @b = 0;
-> WHILE @b < p1 DO
-> SET @b = @b + 1;
-> END WHILE;
-> END;
-> //
mysql> DELIMITER ;
mysql> call exp_whi(100);
mysql> select @b;
+------+
| @b |
+------+
| 100 |
+------+
5、遊標
Mysql查詢語句可能返回多條記錄,如果數據量大則需要在存儲過程中和儲存函數中使用遊標來逐條讀取查詢結果中的記錄。應用程序可以根據需要滾動或瀏覽其中的數據。
(1)聲明遊標
遊標必須在聲明處理程序之前被聲明,並且變量和條件必須在聲明遊標或處理程序之前被聲明。聲明遊標的語句如下:
DECLARE cursor_name CURSOR FOR select_statement
(2)打開遊標
打開遊標的語句如下:
OPEN cursor_name
(3)使用遊標
使用遊標語句如下
FETCH cursor_name INTO var_name [,var_name] ……
var_name:表示將光標中的SELECT 語句查詢出來的信息存入該參數中,var_name必須在聲明光標之前就定義好。
使用遊標時,數據集中的字段需要和INTO語句中定義的變量一一對應,數據集中的數據都fetch完之後,則返回NOT FOUND。
(4)關閉遊標
關閉遊標語句如下:
CLOSE cursor_name
(5)遊標的使用
mysql> DELIMITER //
mysql> CREATE PROCEDURE exp_cur()
-> BEGIN
-> DECLARE done INT DEFAULT FALSE;
-> DECLARE a CHAR(16);
-> DECLARE b, c INT;
-> DECLARE cur1 CURSOR FOR SELECT sname,dept_id FROM student;
-> DECLARE cur2 CURSOR FOR SELECT id FROM course;
-> DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-> OPEN cur1;
-> OPEN cur2;
-> read_loop: LOOP
-> FETCH cur1 INTO a, b;
-> FETCH cur2 INTO c;
-> IF done THEN
-> LEAVE read_loop;
-> END IF;
-> IF b = c THEN
-> INSERT INTO test VALUES (a,b);
-> ELSE
-> INSERT INTO test VALUES (a,c);
-> END IF;
-> END LOOP;
-> CLOSE cur1;
-> CLOSE cur2;
-> END //
mysql> DELIMITER ;
6、查看創建的存儲過程和函數
在創建和存儲過程和函數後可以通過”show status”語句或”show create”語句來查看創建的存儲過程和函數,也可直接從系統的”information_schema”數據庫中查詢。
使用”show status”語句查看存儲過程和函數狀態語句結構如下:
SHOW {PROCEDURE | FUNCTION} STATUS [LIKE ‘pattern’]
# 查看創建的所有以”exp”開頭的存儲過程
mysql> show procedure status like 'exp%' \G
*************************** 1. row ***************************
Db: course
Name: exp_case
Type: PROCEDURE
Definer: root@localhost
……
使用”show create”查看存儲和函數狀態語句如下:
SHOW CREATE {PROCEDURE | FUNCTION} sp_name
從”information_schema.routines”表中查看存儲過程和函數信息的語句結構如下:
Select * from information_schema.routines where routing_name=’sp_name’;
7、修改創建的存儲過程和函數
存儲過程及函數穿件完成後可以通過”alter”語句來修改存儲過程或函數的特性,修改的語句如下:
ALTER {PROCEDURE|FUNCTION} sp_name [characteristic …]
Characteristic參數用於指定存儲函數的特性,取值有:
CONTAINS SQL:表示子程序包含SQL語句,但不包含讀或寫數據的語句。
NO SQL:表示子程序中不包含SQL語句
READS SQL DATA:表示子程序中包含讀數據的語句
MODIFIES SQL DATA:表示子程序中包含寫數據的語句
SQL SECURITY {DEFINER|INVOKER}:指明誰有權限來執行
DEFINER:表示只有定義者自己才能夠執行
INVOKER:表名調用者可以執行
COMMENT ‘string’:表示註釋信息
8、刪除存儲過程及存儲函數
刪除存儲過程及存儲函數使用”drop”語句來刪除,語法格式如下:
DROP {PROCEDURE|FUNCTION} [IF EXISTS] sp_name
刪除一個創建的存儲過程:
mysql> drop procedure exp_whi;
Query OK, 0 rows affected (0.00 sec)
9、mysql觸發器
觸發器是一個特殊的存儲過程,觸發器的作用是當表上有對應SQL語句發生時,則觸發執行。
(1)創建觸發器
創建觸發器的語句如下:
CREATE
[DEFINER = {user | CURRENT_USER }]
TRIGGER trigger_name
Trigger_time trigger_event
ON tbl_name FOR EACH ROW
[trigger_order]
trigger_body
各選項說明:
Definer:用來指定trigger的安全環境
trigger_name:標識觸發器的名稱
Trigger_time:指定觸發器的執行時間,BEFORE代表在數據修改前執行,AFTER代表在修改後執行。
Trigger_event:指定觸發該觸發器的具體事件,INSERT當新的一行數據插入表中時觸發,UPDATE當表的一行數據被修改時觸發,DELETE當表的一行數據被刪除時觸發,當執行insert into … on duplicate key update語句時,當碰到重複行執行update時,則觸發update下的觸發器
tbl_name:標識建立觸發器的表名
Trigger_body:表示觸發器觸發之後要執行的一個或多個語句,在內部可以引用涉及表的字段,OLD.col_name表示行數據被修改或刪除之前的字段數據,NEW.col_name表示行數據被插入或修改之後的字段數據
# 先創建一張表用於在觸發觸發器時備份要修改的數據
mysql> create table student_back(sid int,old_sname varchar(12),sname varchar(12),old_gender int,gender int,update_time time)//
mysql> delimiter //
# 創建觸發器
mysql> create trigger update_trigger
-> after update
-> on student for each row
-> begin
-> insert into student_back values(old.sid,old.sname,new.sname,old.gender,new.gender,now());
-> end;
-> //
mysql> delimiter ;
mysql> update student set gender=1 where sid=1;
# 更新數據後查看備份的數據
mysql> select * from student_back;
+------+-----------+--------+------------+--------+-------------+
| sid | old_sname | sname | old_gender | gender | update_time |
+------+-----------+--------+------------+--------+-------------+
| 1 | Andrew | Andrew | 0 | 1 | 19:12:29 |
+------+-----------+--------+------------+--------+-------------+
(2)查看觸發器
觸發器創建好後可以通過”show triggers”命令查看,也可在”triggers”表中查看觸發器信息。
通過命令查看:show triggers;
通過表查看語句:select * from information_schema.triggers where trigger_name=' trigger_name ' \G
(3)刪除觸發器
觸發器可以通過”drop trigger”語句來刪除,刪除觸發器的語句格式爲:
DROP TRIGGER [schema_name.] trigger_name
schema_name表示數據庫的名稱爲可選參數
# 刪除觸發器
mysql> drop trigger update_trigger;
Query OK, 0 rows affected (0.00 sec)