1. 程式人生 > >第十章 儲存過程和函式

第十章 儲存過程和函式

10.1 建立儲存過程和函式
MySQL中建立儲存過程和函式使用的語句分別是:
CREATE PROCEDURECREATE FUNCTION
注意:使用CALL語句來呼叫儲存過程,只能用輸出變數返回值。
建立儲存過程基本句法:

CREATE PROCEDURE sp_name([proc_parameter]) [characteristics...] routine_body;

CREATE PROCEDURE:用來建立儲存函式的關鍵字;
sp_name:儲存過程的名稱;
proc_parameter:指定儲存過程的引數列表。
(列表形式如下:[IN|OUT|INOUT] param_name type


characteristics:指定儲存過程的特性。
下面程式碼演示了儲存過程的內容,名稱為AvgFruitPrice,返回所有水果的平均價格,輸入程式碼如下:

mysql> CREATE PROCEDURE Proc()
    -> BEGIN
    -> SELECT * FROM fruits;
    -> END //
Query OK, 0 rows affected (0.25 sec)

10.1.2 建立儲存函式
基本語法格式:

CREATE FUNCTION func_name([func_parameter])  RETURNS type [characteristics...] routine_body;

例:建立儲存函式,名稱為NameByZip,該函式返回SELECT語句查詢結果,數值型別為字串型:

mysql> CREATE FUNCTION NameByZip()
    -> RETURNS CHAR(50)
    -> RETURN (SELECT s_name FROM suppliers WHERE s_call='48075');
    -> //
Query OK, 0 rows affected (0.08 sec)

注:DELIMITER ;將結束符換回來。

10.1.3 變數的使用
變數可以在子程式中宣告並使用,這些變數的作用範圍是在BEGIN…END程式中。
1.定義變數
句法:DECLARE var_name[,varname]...date_type[DEFAULT value]


2.為變數賦值
句法:SET var_name=expr [,var_name=expr]...;

10.1.4 定義條件和處理程式
1.定義條件
句法:
DECIMAL condition_name CONDITION [condition_type] [condition_type]: SQLSTATE[VALUE] sqlstate_value | mysql_error_code

例:定義“ERROR 1148(42000)”錯誤,名稱為command_not_allowed。可以用兩種不同的方法來定義:

//方法一:使用salstate_value
DECLARE command_not_allowed CONDITION FOR SQLSTATE '42000';
//方法二:使用mysql_error_code
DELARE command_not_allow CONDITION FOR 1148

2.定義處理程式
句法:

DELARE handler_type HANDLER FOR condition_value[,...] sp_statement
handler_type:
     CONTINUE | EXIT | UNDO
 condition_value:
     SQLSTATE[VALUE]sqlstate_value
     |condition_name
     |SQLWARNING
     |NOT FOUND
     |SQLEXCEPTION
     |mysql_error_code

handler_type(錯誤處理方式):
CONTINUE:遇到錯誤不處理;
EXIT:遇到錯誤馬上退出;
UNDO:遇到錯誤後撤回之前的操作,MySQL中暫時不支援這樣的操作。

condition_value:表示錯誤型別。
sp_statement引數為程式語句段,表示在遇到錯誤時,需要執行的儲存過程或函式。

10.1.5 游標的使用
1.宣告游標
句法:
DECLARE cursor_name CURSOR FOR select_statement
cursor_name引數表示游標的名稱;
select_statement引數表示SELECT語句的內容,返回用於建立游標的結果集。

2.開啟游標
句法:OPEN cursor_name{游標名稱}

3.關閉游標
句法:CLOSE cursor_name{游標名稱}

10.1.6 流程控制的使用

  1. IF語句
    程式碼示例:
IF val IS NULL
     THEN SELECT 'val is NULL';
     ELSE SELECT 'val is not NULL';
END IF;
  1. CASE語句
CASE val
     WHEN 1 THEN SELECT 'val is 1’;
     WHEN 2 THEN SELECT 'val is 2’;
     ELSE SELECT 'val is not 1 or 2’;
END CASE
  1. LOOP語句
    例:
DELARE id INT DEFAULT 0;
add_loop:LOOP
         SET id=id+1; 
           IF id>=10 THEN LEAVE add_loop;
           END IF;
END LOOP add_loop;
  1. LEAVE語句
    例:
add_num:LOOP
       SET @[email protected]+1;
       IF @count =50 THEN LEAVE add_num;
END LOOP add_num;
  1. ITERATE語句
    語句將執行順序轉到語句段開頭處。
    ITERATE語句只可以出現在LOOP、REPEATE和WHILE語句內。
  2. REPEAT語句
  3. WHILE語句

10.2 呼叫儲存過程和函式
10.2.1 呼叫儲存過程

CALL sp_name([parameter[,...]])

10.2.2 呼叫儲存函式
使用SELECT.
10.3檢視儲存過程和函式
10.3.1 SHOW STATUS語句檢視儲存過程和函式的狀態

SHOW {PROCEDURE|FUNCTION} STATUS [LIKE 'pattern']

程式碼示例:

SHOW PROCEDURE STATUS LIKE 'C%'\G;
*************************** 1. row ***************************
                  Db: sys
                Name: create_synonym_db
                Type: PROCEDURE
             Definer: [email protected]
            Modified: 2018-09-28 18:59:36
             Created: 2018-09-28 18:59:36
       Security_type: INVOKER
             Comment:
 Description

 Takes a source database name and synonym name, and then creates the
 synonym database with views that point to all of the tables within
 the source database.

 Useful for creating a "ps" synonym for "performance_schema",
 or "is" instead of "information_schema", for example.

 Parameters

 in_db_name (VARCHAR(64)):
 The database name that you would like to create a synonym for.
 in_synonym (VARCHAR(64)):
 The database synonym name.

 Example

 mysql> SHOW DATABASES;
 +--------------------+
 | Database           |
 +--------------------+
 | information_schema |
 | mysql              |
 | performance_schema |
 | sys                |
 | test               |
 +--------------------+
 5 rows in set (0.00 sec)

 mysql> CALL sys.create_synonym_db('performance_schema', 'ps');
 +---------------------------------------+
 | summary                               |
 +---------------------------------------+
 | Created 74 views in the `ps` database |
 +---------------------------------------+
 1 row in set (8.57 sec)

 Query OK, 0 rows affected (8.57 sec)

 mysql> SHOW DATABASES;
 +--------------------+
 | Database           |
 +--------------------+
 | information_schema |
 | mysql              |
 | performance_schema |
 | ps                 |
 | sys                |
 | test               |
 +--------------------+
 6 rows in set (0.00 sec)

 mysql> SHOW FULL TABLES FROM ps;
 +------------------------------------------------------+------------+
 | Tables_in_ps                                         | Table_type |
 +------------------------------------------------------+------------+
 | accounts                                             | VIEW       |
 | cond_instances                                       | VIEW       |
 | events_stages_current                                | VIEW       |
 | events_stages_history                                | VIEW       |
 ...

character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
1 row in set (0.27 sec)

ERROR:
No query specified

10.3.2 SHOW CREATE語句檢視儲存過程和函式的定義
除了SHOW STATUS之外,MySQL還可以使用SHOW CREATE語句檢視儲存過程和函式的狀態。

SHOW CREATE {PROCEDURE | FUNCTION} sp_name

例:

mysql> SHOW CREATE FUNCTION test.CountPro\G;

10.3.3 從information_schema.Routines表中檢視儲存過程和函式的資訊
語法:
SELECT * FROM information_schema.Rountines WHERE ROUNTINE_NAME='sp_name';

10.4 修改儲存過程和函式

ALTER {PROCEDURE | FUNCTION} sp_name[characteric...]

10.5 刪除儲存過程和函式

DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name

10.6 綜合案例
01 建立一個名為sch的資料表,並向表中插入資料

mysql> CREATE TABLE sch(
    -> id INT,
    -> name VARCHAR(50),
    -> glass VARCHAR(50)
    -> );
Query OK, 0 rows affected (0.58 sec)

mysql> INSERT INTO sch VALUES(1,'xiaoming','glass1'),
    -> (2,'xiaojun','glass2');
Query OK, 2 rows affected (0.11 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> DESC sch;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(50) | YES  |     | NULL    |       |
| glass | varchar(50) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.04 sec)

mysql> SELECT * FROM sch;
+------+----------+--------+
| id   | name     | glass  |
+------+----------+--------+
|    1 | xiaoming | glass1 |
|    2 | xiaojun  | glass2 |
+------+----------+--------+
2 rows in set (0.00 sec)

02建立一個可以統計表格內記錄條數的儲存函式,函式名為count_sch


mysql> DELIMITER //
mysql> CREATE FUNCTION count_sch()
    -> RETURNS INT
    -> RETURN(SELECT COUNT(*) FROM sch);
    -> //
Query OK, 0 rows affected (0.10 sec)

mysql> SELECT count_sch()//
+-------------+
| count_sch() |
+-------------+
|           2 |
+-------------+
1 row in set (0.18 sec)

03建立一個儲存過程add_id在同時使用前面建立的儲存函式返回表sch中的記錄數,計算表中所以的id之和

mysql> DELIMITER //
mysql> CREATE PROCEDURE add_id(out count INT)
    -> BEGIN
    -> DECLARE itmp INT;
    -> DECLARE cur_id CURSOR FOR SELECT id FROM sch;
    -> DECLARE EXIT HANDLER FOR NOT FOUND CLOSE cur_id;
    -> SELECT count_sch() INTO count;
    -> SET @sum=0;
    -> OPEN cur_id;
    -> REPEAT
    -> FETCH cur_id INTO itmp;
    -> IF itmp<10
    -> THEN SET @[email protected]+itmp;
    -> END IF;
    -> UNTIL 0 END REPEAT;
    -> CLOSE cur_id;
    -> END //
Query OK, 0 rows affected (0.10 sec)

mysql> SELECT @a,@sum //
+------+------+
| @a   | @sum |
+------+------+
| NULL | NULL |
+------+------+
1 row in set (0.00 sec)