MySQL存儲過程瞭解一下

簡介

存儲過程(Stored Procedure)是在大型數據庫系統中,一組爲了完成特定功能的SQL 語句集,它存儲在數據庫中,一次編譯後永久有效,用戶經過指定存儲過程的名字並給出參數(若是該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象。mysql

存儲過程的使用

建立存儲過程

語法:sql

CREATE PROCEDURE 存儲過程名( IN|OUT|INOUT 參數名 數據類型 , ...)
BEGIN
	...
END;

MySQL存儲過程的參數類型:數據庫

  1. IN,表示存儲過程的輸入參數,該參數的值將會傳遞給存儲過程,在存儲過程當中能夠對該參數進行修改,可是在存儲過程返回時,該參數值不會被返回,至關於在存儲過程當中對該參數的修改對調用者來講是不可見的。oop

  2. OUT,表示存儲過程的輸入參數,該參數的值會在存儲過程當中初始化爲NULL,當存儲過程返回時,該值也會被返回,調用者能夠看到被修改後的值。fetch

  3. 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語句

語法:

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語句

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語句

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語句

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語句

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            |
+----------------------+
| 小明小米小看小阿小鬼 |
+----------------------+
關於SQLSTATE '02000'

在使用遊標時,能夠經過FETCH將數據集中的數據保存到變量中進行處理,可是當整個數據集已經FETCH結束的時候,再去FETCH就會拋異常:

1329 - No data - zero rows fetched, selected, or processed

該異常對應的SQLSTATE爲02000,因此須要指定句柄捕獲這種異常狀況來給標誌賦值,後續就能夠經過這個標誌來判斷數據集循環讀取結束。

異常信息詳見:Error Reference

相關文章
相關標籤/搜索