MYSQL的儲存過程
儲存過程的創建、修改、刪除、調用
創建儲存過程
語法:
CREATE PROCEDURE proc_name ([proc_parameter]) [characteristics...] body
講解:
CREATE PROCEDURE:創建存儲過程關鍵字
proc_name:存儲過程名稱
proc_parameter:參數列表,可選,格式:[IN | OUT | INOUT] param_name type
IN:輸入參數
OUT:輸出參數
INOUT:既可以輸入也可以輸出
param_name:參數名稱
type:參數類型,MySQL中的任意類型,如varchar等
characteristics:指定存儲過程特性,取值如下:
LANGUAGE SQL:說明body部分由SQL語句組成,LANGUAGE可選值只有SQL
[NOT] DETERMINISTIC:指明存儲過程執行結果是否確定。默認值:NOT DETERMINISTIC
DETERMINISTIC:結果確定,每次執行存儲過程時,相同的輸入會得到相同的輸出
NOT DETERMINISTIC:結果不確定,相同輸入可能得到不同輸出。
{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}:指定子程序使用存儲過程的限制。默認值:CONTAINS SQL
CONTAINS SQL:說明子程序包含SQL語句,但是不包含寫數據語句
NO SQL:說明子程序不包含SQL語句
READS SQL DATA:說明子程序包含讀數據讀數據語句
MODIFIES SQL DATA:說明子程序包含寫數據語句
SQL SECURITY {DEFINER | INVOKER}:指明誰有權限執行,默認值:DEFINER
DEFINER:只有定義者才能執行
INVOKER:擁有權限的調用者纔可以執行
COMMNET:註釋信息
創建調用
語法:
CALL proc_name ([parameter[,...]])
案例:
DELIMITER $$
CREATE PROCEDURE proc_countByName(IN uname VARCHAR(100), OUT total INT)
BEGIN
SELECT COUNT(*) INTO total FROM njit_user WHERE NAME LIKE CONCAT('%', uname, '%');
END $$
刪除存儲過程
語法:
DROP {PROCEDURE | FUNCTION} [IF EXISTS] proc_name
刪除:
DROP PROCEDURE proc_countByName;
DROP PROCEDURE IF EXISTS proc_countByName;
修改
語法:
ALTER {PROCEDURE | FUNCTION} proc_or_func [characterustic...]
說明:
{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}:指定子程序使用存儲過程的限制。
CONTAINS SQL:說明子程序包含SQL語句,但是不包含寫數據語句
NO SQL:說明子程序不包含SQL語句
READS SQL DATA:說明子程序包含讀數據讀數據語句
MODIFIES SQL DATA:說明子程序包含寫數據語句
SQL SECURITY {DEFINER | INVOKER}:指明誰有權限執行,默認值:DEFINER
DEFINER:只有定義者才能執行
INVOKER:擁有權限的調用者纔可以執行
COMMNET:註釋信息
查看狀態
語法:
SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'parttern']
說明:
這個語句是MySQL的擴展,它返回子程序的特徵,如數據庫、名字、類型、創建者及創建和修改日期。如果沒有指定樣式,根據使用的語句,所有存儲程序或存儲函數的信息都被列出。PROCEDURE和FUNCTION分別表示查看存儲過程和函數;LIKE語句表示匹配存儲過程或函數名稱。
案例:
SHOW PROCEDURE STATUS LIKE 'proc_%';
儲存過程的基礎命令
### 創建存儲過程
-- 定義結束符[爲了PROCEDURE的結束符與mysql的普通語句不同]
delimiter //
-- 如果該儲存過程存在就刪除
DROP PROCEDURE IF EXISTS in_param;
-- 創建一個儲存過程[in_param],需要傳入參數inParam
CREATE PROCEDURE in_param(INOUT inParam VARCHAR(50))
-- 開始標識符
BEGIN
-- 定義變量
DECLARE var_param1 VARCHAR(50) DEFAULT "自定義變量默認值var_param1";
-- 獲取數據值
SELECT var_param1;
-- 重新改變數據值
SET var_param1='改變自定義的屬性值';
-- 獲取數據值
SELECT var_param1;
-- 重新賦值
select "運行into儲存值" into intoParam;
select intoParam;
-- 語句執行結束符
END //
-- 重新改變數據的結束的標識符
delimiter ;
### 調用存儲過程
語法:call sp_name()
注意:存儲過程名稱後面必須加括號,哪怕該存儲過程沒有參數傳遞
### 刪除存儲過程
語法:drop procedure sp_name
注意:不能在一個存儲過程中刪除另一個存儲過程,只能調用另一個存儲過程
儲存過程的簡單使用案例
-- 定義結束符[爲了PROCEDURE的結束符與mysql的普通語句不同]
delimiter //
-- 如果該儲存過程存在就刪除
DROP PROCEDURE IF EXISTS in_param;
-- 創建一個儲存過程[in_param],需要傳入參數inParam
CREATE PROCEDURE in_param(INOUT inParam VARCHAR(50))
-- 開始標識符
BEGIN
-- 定義變量
DECLARE var_param1 VARCHAR(50) DEFAULT "自定義變量默認值var_param1";
DECLARE intoParam VARCHAR(50) DEFAULT "自定義變量默認值intoParam";
-- 獲取數據值
SELECT var_param1;
SELECT inParam;
-- 重新改變數據值
SET var_param1='改變自定義的屬性值';
SET inParam='傳入值的修改';
-- 獲取數據值
SELECT var_param1;
SELECT inParam;
-- 重新賦值
select "運行into儲存值" into intoParam;
select intoParam;
-- 語句執行結束符
END //
-- 重新改變數據的結束的標識符
delimiter ;
-- 調用儲存過程[儲存過程是傳入的參數當我們select @inParamStr輸出的是原始值,而不是過程內部修改之後的值,如果我們更改參數類型爲inout,則會輸出]
set @inParamStr="傳入參數";
CALL in_param(@inParamStr);
select @inParamStr;
儲存過程的變量的定義
變量的定義
DECLARE [相同屬性的變量x ......] VARCHAR(50) DEFAULT "默認的初始化值";
改變變量值
SET x= "修改之後的值";
改變變量值
select "查詢改變之後的值" into x;
變量範圍(作用域)
一個變量有自己的範圍(作用域),它用來定義它的生命週期。 如果在存儲過程中聲明一個變量,那麼當達到存儲過程的END語句時,它將超出範圍,因此在其它代碼塊中無法訪問。
如果您在BEGIN END塊內聲明一個變量,那麼如果達到END,它將超出範圍。 可以在不同的作用域中聲明具有相同名稱的兩個或多個變量,因爲變量僅在自己的作用域中有效。 但是,在不同範圍內聲明具有相同名稱的變量不是很好的編程習慣。
以@符號開頭的變量是會話變量。直到會話結束前它可用和可訪問。
定義條件和處理程序
#定義條件
語法:DECLARE cond_name CONDITION FOR [cond_type]
解析:[cond_type]:SQLSTATE [VALUE] sqlstate_value(可選項) | mysql_erroe_code(可選項)
cond_name:條件名稱
cond_type:條件類型,用於定義MySQL的錯誤,SQLSTATE是長度爲5的字符串類型的錯誤代碼;mysql_error_code是數值類型的錯誤代碼。例如ERROR 1142(42000),sql_state_value的值是'42000',mysql_error_code的值是1142。
示例:
-- 使用SQLSTATE
DECLARE cond_error CONDITION FOR SQLSTATE '42000';
-- 使用mysql_error_code
DECLARE cond_error CONDITION FOR 1148;
#定義處理程序
語法:DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement
解析:handler_type:指定錯誤處理方式
CONTINUE:遇到錯誤不處理,繼續執行
EXIT:遇到錯誤立即退出
UNDO:遇到錯誤撤回之前的操作
condition_value:表示錯誤類型
SQLSTATE [VALUE] sqlstate_value:包含5個字符的字符串錯誤值
mysql_error_code:數值類型的錯誤代碼
cond_name:定義條件的名稱,見第一節
SQLWARNING:匹配所有以01開頭的SQLSTATE錯誤代碼
NOT FOUND:匹配所有以02開頭的SQLSTATE錯誤代碼
SQL EXCEPTION:匹配所有沒有被SQLWARNING或NOT FOUND捕獲的SQLSTATE錯誤代碼
sp_statement: 程序語句段
程序語句段,表示在遇到定義的錯誤時執行的存儲過程或函數。
示例:
-- 捕獲SQLSTATE
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info='NO_SUCH_TABLE';
-- 捕獲mysql_error_code
DECLARE CONTINUE HANDLER FOR SQLSTATE '1146' SET @info='NO_SUCH_TABLE' ;
-- 捕獲定義條件
DECLARE no_such_table CONDITION FOR 1146;
DECLARE CONTINUE HANDLER FOR no_such_table SET @info='NO_SUCH_TABLE';
-- 捕獲SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING set @info='ERROR';
-- 捕獲NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND set @info='NO_SUCH_TABLE';
-- 捕獲SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION set @info='ERROR';
-- 捕獲所有異常
DECLARE EXIT HANDLER FOR SQLWARNING, NOT FOUND,SQLEXCEPTION BEGIN ... END;
#存儲過程示例
DELIMITER $$
CREATE PROCEDURE proc_del_user(IN uid INT, OUT rowCount INT, OUT msg VARCHAR(200))
BEGIN
-- 出錯標記
DECLARE t_error INT DEFAULT 0;
-- 定義出錯處理程序
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error = 1;
-- 刪除用戶
DELETE FROM t_user WHERE id = uid;
-- 異常處理
IF t_error = 0 THEN
SET msg = 'success';
ELSE
SET msg = 'error';
END IF;
-- 設置真正影響行數的行數,修改了但是沒有修改值都不計入
SET rowCount = ROW_COUNT();
SELECT rowCount, msg;
END $$
-- 調用儲存過程
CALL proc_del_user(1, @rowCount, @msg);
SELECT @rowCount, @msg;
光標的使用
光標:查詢語句可能查詢出多條記錄,在存儲過程和函數中使用光標來逐條讀取查詢結果集中的記錄
步驟:聲明光標->打開光標->使用光標->關閉光標;
光標必須聲明在處理程序之前,並且聲明在變量和條件之後。
語法:
聲明光標:DECLARE cursor_name CURSOR FOR select_statement(sql命令);
cursor_name參數表示光標的名稱;select_statement參數表示SELECT語句的內容,返回一個用於創建光標的結果集
打開光標:OPEN cursor_name;
cursor_name參數表示光標的名稱。
使用光標:FETCH cur_employee INTO var_name[,var_name…] ;
cursor_name參數表示光標的名稱;var_name參數表示將光標中的SELECT語句查詢出來的信息存入該參數中。var_name必須在聲明光標之前就定義好
關閉光標:CLOSE cursor_name ;
cursor_name參數表示光標的名稱。關閉之後就不能使用FETCH來使用光標了
例子:
begin
##定義變量
declare my_id varchar(32);
declare my_name varchar(50);
DECLARE done INT DEFAULT FALSE;
#創建遊標並存儲數據,
DECLARE My_Cursor CURSOR FOR ( SELECT tid,tname FROM `teacher` );
#遊標中內容執行完設置done爲1
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
#設置手動提交
set autocommit=0;
#打開遊標
OPEN My_Cursor;
#執行循環
myLoop: LOOP
#判斷是否結束循環
IF done THEN
LEAVE myLoop;
END IF;
#取出遊標中的值
FETCH My_Cursor into my_id,my_name;
#更新數據
UPDATE course SET cname = my_name WHERE teacher_id = my_id ;
END LOOP myLoop;
#釋放遊標
CLOSE My_Cursor;
#提交
COMMIT;
END
流程控制
流程控制:[IF語句、CASE語句、LOOP語句、LEAVE語句、ITERATE語句、REPEAT語句、WHILE]
語法:
IF語句:[類似於java的if-else if-else]search_condition參數表示條件判斷語句;statement_list參數表示不同條件的執行語句[MYSQL還有一個IF()函數,他不同於這裏描述的IF語句]
語法:
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF
案例:
IF age>20 THEN SET @count1=@count1+1;
ELSEIF age=20 THEN SET @count2=@count2+1;
ELSE SET @count3=@count3+1;
END IF;
CASE語句:[類似於java的switch]case_value參數表示條件判斷的變量;when_value參數表示變量的取值;statement_list參數表示不同when_value值的執行語句
語法:
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
案例:
CASE age
WHEN 20 THEN SET @count1=@count1+1;
ELSE SET @count2=@count2+1;
END CASE ;
CASE另一種寫法:[類似於java的switch]CASE search_condition參數表示條件判斷語句;statement_list參數表示不同條件的執行語句;
語法:
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE
案例:
CASE
WHEN age=20 THEN SET @count1=@count1+1;
ELSE SET @count2=@count2+1;
END CASE;
注意:注意:這裏的CASE語句和“控制流程函數”裏描述的SQL CASE表達式的CASE語句有輕微不同。這裏的CASE語句不能有ELSE NULL子句並且用END CASE替代END來終止!!
LOOP語句:[類似於java的for]LOOP語句可以使某些特定的語句重複執行,實現一個簡單的循環,但是LOOP語句本身沒有停止循環的語句,必須是遇到LEAVE語句等才能停止循環
語法:begin_label參數和end_label參數分別表示循環開始和結束的標誌,這兩個標誌必須相同,而且都可以省略;statement_list參數表示需要循環執行的語句
[begin_label:] LOOP
statement_list
END LOOP [end_label]
案例:因爲沒有跳出循環的語句,這個循環成了一個死循環
add_num: LOOP
SET @count=@count+1;
END LOOP add_num ;
LEAVE語句:[類似於java的return]LEAVE語句主要用於跳出循環控制
語法:label參數表示循環的標誌
LEAVE label
案例:
add_num: LOOP
SET @count=@count+1;
IF @count=100 THEN
LEAVE add_num ;
END LOOP add_num ;
ITERATE語句:[類似於java的continue]ITERATE語句也是用來跳出循環的語句。但是,ITERATE語句是跳出本次循環,然後直接進入下一次循環;ITERATE語句只可以出現在LOOP、REPEAT、WHILE語句內
語法:label參數表示循環的標誌
ITERATE label
案例:
add_num: LOOP
SET @count=@count+1;
IF @count=100 THEN
LEAVE add_num ;
ELSE IF MOD(@count,3)=0 THEN
ITERATE add_num;
SELECT * FROM employee ;
END LOOP add_num ;
REPEAT語句:[類似於Java的do-while]REPEAT語句是有條件控制的循環語句。當滿足特定條件時,就會跳出循環語句
語法:statement_list參數表示循環的執行語句;search_condition參數表示結束循環的條件,滿足該條件時循環結束
[begin_label:] REPEAT
statement_list
UNTIL search_condition
END REPEAT [end_label]
案例:
REPEAT
SET @count=@count+1;
UNTIL @count=100
END REPEAT ;
WHILE語句:[類似於Java的while]WHILE語句也是有條件控制的循環語句。但WHILE語句和REPEAT語句是不一樣的。WHILE語句是當滿足條件時,執行循環內的語句
語法:search_condition參數表示循環執行的條件,滿足該條件時循環執行,statement_list參數表示循環的執行語句
[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
案例:
WHILE @count<100 DO
SET @count=@count+1;
END WHILE ;