1. 程式人生 > 實用技巧 >MySQL學習筆記(11):儲存過程和函式

MySQL學習筆記(11):儲存過程和函式

本文更新於2019-06-23,使用MySQL 5.7,作業系統為Deepin 15.4。

目錄

SQL語句

建立儲存過程或函式

建立儲存過程:

CREATE PROCEDURE name ({[IN|OUT|INOUT] param type}[, ...])
[characteristic]
body

建立函式:

CREATE FUNCTION name ({param type}[, ...]) RETURNS type
[characteristic]
body

type表示資料型別。

characteristic表示特徵值,特徵值目前只是提供資訊給伺服器,定義如下:

LANGUAGE SQL
|[NOT] DETERMINISTIC
|{CONTAINS SQL|NO SQL|READS SQL DATA|MODIFIES SQL DATA}
|SQL SECURITY {DEFINER|INVOKER}
|COMMENT 'string'
  • LANGUAGE SQL:說明body是使用SQL編寫的。該值是預設的。
  • [NOT] DETERMINISTIC:說明是確定的,即是否同樣的輸入產生同樣的輸出。預設為NOT DETERMINISTIC
  • CONTAINS SQL|NO SQL|READS SQL DATA|MODIFIES SQL DATA:目前並沒有根據此特徵值約束儲存過程實際對資料的使用。CONTAINS SQL
    表示不包含讀寫語句;NO SQL表示不包含SQL語句;READS SQL DATA表示包含讀語句不包含寫語句;MODIFIES SQL DATA表示包含寫語句。預設為CONTAINS SQL
  • SQL SECURITY {DEFINER|INVOKER}:表示使用建立者的許可權來執行,還是使用呼叫者的許可權來執行。預設為DEFINER
  • COMMENT 'string':註釋。

body由BEGINEND包起,其中可以定義變數、條件、處理、遊標,以及使用流程控制語句跳轉邏輯。

儲存過程和函式的CREATE語法不支援OR REPLACE

儲存過程和函式的區別:函式一定有返回值,儲存過程一定沒有返回值;函式的引數只能使用IN

型別,儲存過程的引數可使用INOUTINOUT型別。

MySQL的儲存過程和函式中允許包含DDL語句,允許執行提交或回滾,允許呼叫其他儲存過程或函式,但是是不允許執行LOAD DATA INFILE語句。

通常在執行建立儲存過程或函式前,使用DELIMITER ;;命令將語句的結束符從;修改成其他符號(示例使用;;)。在建立完畢後,通過DELIMITER ;命令將結束符還原。這樣可避免儲存過程定義中的;被錯誤解析為結束符。

修改儲存過程或函式

ALTER PROCEDURE|FUNCTION name
[characteristic]

characteristic特徵值如下:

{CONTAINS SQL|NO SQL|READS SQL DATA|MODIFIES SQL DATA}
|SQL SECURITY {DEFINER|INVOKER}
|COMMENT 'string'

刪除儲存過程或函式

DROP PROCEDURE|FUNCTION [IF EXISTS] name

一次只能刪除一個儲存過程或函式。

呼叫儲存過程或函式

CALL name(param[, ...])

如果是輸出引數,需傳入變數,如:@xxx

變數、條件、處理、遊標

變數、條件、處理、遊標都通過DECLARE定義,但它們之間是有先後順序的:變數和條件必須在最前面宣告,然後才是遊標的宣告,最後才是處理的宣告。

變數

變數不區分大小寫,作用範圍只能在BEGIN ... END塊中,可以用在巢狀的塊中。變數的定義必須寫在複合語句的開頭,並且在其他語句的前面。

DECLARE var[, ...] type [DEFAULT value]

變數直接賦值:

SET {var = value}[, ...]

變數通過查詢賦值,這要求查詢返回的結果只有一行:

SELECT colname[, ...] INTO var[, ...] FROM ...

FROM後面的子句同普通的SELECT查詢,在此省略。

條件

DECLARE condition_name CONDITION FOR
{SQLSTATE [VALUE] value}|mysql_error_code

條件枚的含義如下:

  • SQLSTATE [VALUE] value:SQLSTATE程式碼,為一個字串。
  • mysql_error_code:mysql_error_code值,為一個整數。

處理

DECLARE CONTINUE|EXIT|UNDO HANDLER FOR
{SQLSTATE [VALUE] value|condition_name|SQLWARNING|NOT FOUND|SQLEXCEPTION|mysql_error_code}[, ...]
sp_statement

處理型別列舉值的含義:

  • CONTINUE:繼續執行後面的語句。
  • EXIT:執行終止。
  • UNDO:前面已執行的語句撤銷,目前還不支援。

條件枚的含義如下:

  • SQLSTATE [VALUE] value:SQLSTATE程式碼,為一個字串。
  • condition_nameDECLARE定義的CONDITION名。
  • SQLWARNING:所有以01開頭的SQLSTATE程式碼的速記。
  • NOT FOUND:所有以02開頭的SQLSTATE程式碼的速記。
  • SQLEXCEPTION:所有沒有被SQLWARNINGNOT FOUND捕獲的SQLSTATE程式碼的速記。
  • mysql_error_code:mysql_error_code值,為一個整數。

遊標

宣告遊標:

DECLARE cursor_name CURSOR FOR select_statement

開啟遊標:

OPEN cursor_name

讀取遊標:

FETCH cursor_name INTO var[, ...]

關閉遊標:

CLOSE cursor_name

流程控制

IF

IF condition1 THEN statement_list1
[ELSEIF condition2 THEN statement_list2]
[...]
[ELSE statement_list3]
END IF

CASE

CASE case_value
WHEN value1 THEN statement_list1
[...]
[ELSE statement_list2]
END CASE

或:

CASE
WHEN condition1 THEN statement_list1
[...]
[ELSE statement_list2]
END CASE

LEAVE

從標註的流程中退出,通常和BEGIN ... END或迴圈一起使用。

LEAVE label

ITERATE

ITERATE必須用在迴圈中,作用是跳過當前迴圈的剩下語句,進入下一輪迴圈。

ITERATE label

LOOP

通常需在statement_list中指定退出條件,否則為死迴圈。

[begin_label:] LOOP
	statement_list
END LOOP [end_label]

WHILE

當滿足條件時執行迴圈。會在首次迴圈執行前判斷條件,故迴圈最少執行0次。

[begin_label:] WHILE condition DO
statement_list
END WHILE [end_label]

REPEAT

當滿足條件時退出迴圈。會在首次迴圈執行後判斷條件,故迴圈最少執行1次。

[begin_label:] REPEAT
	statement_list
UNTIL condition
END REPEAT [end_label]

示例

儲存過程定義示例如下:

DELIMITER ;;

CREATE PROCEDURE sp_test(IN id INT, OUT sum INT)
BEGIN
	DECLARE var_value, var_sum INT DEFAULT 0;
	DECLARE flag INT DEFAULT 1;
	DECLARE cur CURSOR FOR SELECT value FROM t WHERE tid = id;
	DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 0;
	OPEN cur;
	loop_cur: LOOP
		FETCH cur INTO var_value;
		IF flag = 0 THEN
			LEAVE loop_cur;
		END IF;
		var_sum = var_sum + var_value;
	END LOOP;
	CLOSE cur;
END;;

DELIMITER ;