天天看點

MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗

8.存儲過程實驗

8.1存儲過程定義

存儲過程是一組為了完成特定功能的 SQL 語句集合。使用存儲過程的目的是将常用或複雜的工作預先用 SQL 語句寫好并用一個指定名稱存儲起來,這個過程經編譯和優化後存儲在資料庫伺服器中,是以稱為存儲過程。當以後需要資料庫提供與已定義好的存儲過程的功能相同的服務時,隻需調用“CALL存儲過程名字”即可自動完成。

8.2存儲過程的優點

1) 封裝性

通常完成一個邏輯功能需要多條 SQL 語句,而且各個語句之間很可能傳遞參數,是以,編寫邏輯功能相對來說稍微複雜些,而存儲過程可以把這些 SQL 語句包含到一個獨立的單元中,使外界看不到複雜的 SQL 語句,隻需要簡單調用即可達到目的。并且資料庫專業人員可以随時對存儲過程進行修改,而不會影響到調用它的應用程式源代碼。

2) 可增強 SQL 語句的功能和靈活性

存儲過程可以用流程控制語句編寫,有很強的靈活性,可以完成複雜的判斷和較複雜的運算。

3) 可減少網絡流量

由于存儲過程是在伺服器端運作的,且執行速度快,是以當客戶計算機上調用該存儲過程時,網絡中傳送的隻是該調用語句,進而可降低網絡負載。

4) 高性能

當存儲過程被成功編譯後,就存儲在資料庫伺服器裡了,以後用戶端可以直接調用,這樣所有的 SQL 語句将從伺服器執行,進而提高性能。但需要說明的是,存儲過程不是越多越好,過多的使用存儲過程反而影響系統性能。

5) 提高資料庫的安全性和資料的完整性

存儲過程提高安全性的一個方案就是把它作為中間元件,存儲過程裡可以對某些表做相關操作,然後存儲過程作為接口提供給外部程式。這樣,外部程式無法直接操作資料庫表,隻能通過存儲過程來操作對應的表,是以在一定程度上,安全性是可以得到提高的。

6) 使資料獨立

資料的獨立可以達到解耦的效果,也就是說,程式可以調用存儲過程,來替代執行多條的 SQL 語句。這種情況下,存儲過程把資料同使用者隔離開來,優點就是當資料表的結構改變時,調用表不用修改程式,隻需要資料庫管理者重新編寫存儲過程即可。

8.3建立存儲過程

文法格式如下:

CREATE PROCEDURE <過程名> ( [過程參數[,…] ] ) <過程體>

[過程參數[,…] ] 格式

[ IN | OUT | INOUT ] <參數名> <類型>

文法說明如下:

1) 過程名

​ 存儲過程的名稱,預設在目前資料庫中建立。若需要在特定資料庫中建立存儲過程,則要在名稱前面加上資料庫的名稱,即 db_name.sp_name。需要注意的是,名稱應當盡量避免選取與 MySQL 内置函數相同的名稱,否則會發生錯誤。

2) 過程參數

​ 存儲過程的參數清單。其中,

< 參數名 >

為參數名,

< 類型 >

為參數的類型(可以是任何有效的 MySQL 資料類)。當有多個參數時,參數清單中彼此間用逗号分隔。存儲過程可以沒有參數(此時存儲過程的名稱後仍需加上一對括号),也可以有 1 個或多個參數。

​ MySQL 存儲過程支援三種類型的參數,即輸入參數、輸出參數和輸入/輸出參數,分别用 IN、OUT 和 INOUT 三個關鍵字辨別。其中,輸入參數可以傳遞給一個存儲過程,輸出參數用于存儲過程需要傳回一個操作結果的情形,而輸入/輸出參數既可以充當輸入參數也可以充當輸出參數。

​ 需要注意的是,參數的取名不要與資料表的列名相同,否則盡管不會傳回出錯資訊,但是存儲過程的 SQL 語句會将參數名看作列名,進而引發不可預知的結果。

3) 過程體

​ 存儲過程的主體部分,也稱為存儲過程體,包含在過程調用的時候必須執行的 SQL 語句。這個部分以關鍵字 BEGIN 開始,以關鍵字 END 結束。若存儲過程體中隻有一條 SQL 語句,則可以省略 BEGIN-END 标志。

​ 在存儲過程的建立中,經常會用到一個十分重要的 MySQL 指令,即 DELIMITER 指令,特别是對于通過指令行的方式來操作 MySQL 資料庫的使用者,更是要學會使用該指令。

​ 注意:在 MySQL 中,伺服器處理 SQL 語句預設是以分号作為語句結束标志的。然而,在建立存儲過程時,存儲過程體可能包含有多條 SQL 語句,這些 SQL 語句如果仍以分号作為語句結束符,那麼 MySQL 伺服器在處理時會以遇到的第一條 SQL 語句結尾處的分号作為整個程式的結束符,而不再去處理存儲過程體中後面的 SQL 語句,這樣顯然不行。

為解決以上問題,通常使用 DELIMITER 指令将結束指令修改為其他字元。文法格式如下:

DELIMITER $$
           

文法說明如下:

  • $$ 是使用者定義的結束符,通常這個符号可以是一些特殊的符号,如兩個“?”或兩個“¥”等。
  • 當使用 DELIMITER 指令時,應該避免使用反斜杠“\”字元,因為它是 MySQL 的轉義字元。

在 MySQL 指令行用戶端輸入如下 SQL 語句。

mysql > DELIMITER ??
           

成功執行這條 SQL 語句後,任何指令、語句或程式的結束标志就換為兩個問号“??”了。

若希望換回預設的分号“;”作為結束标志,則在 MySQL 指令行用戶端輸入下列語句即可:

注意:DELIMITER 和分号“;”之間一定要有一個空格。在建立存儲過程時,必須具有 CREATE ROUTINE 權限。

8.3.1建立存儲過程例子

mysql> delimiter $$
mysql> create procedure show_employeeInfo()
    -> begin
    -> select *from employee;
    -> end$$
           

8.4檢視存儲過程結構:

MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗

8.5删除存儲過程:

文法說明如下:

①過程名:指定要删除的存儲過程的名稱。

②IF EXISTS:指定這個關鍵字,用于防止因删除不存在的存儲過程而引發的錯誤。

**注意:**存儲過程名稱後面沒有參數清單,也沒有括号,在删除之前,必須确認該存儲過程沒有任何依賴關系,否則會導緻其他與之關聯的存儲過程無法運作。

MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗

8.6修改存儲過程的文法格式如下:

特征

指定了存儲過程的特性,可能的取值有:

①CONTAINS SQL 表示子程式包含 SQL 語句,但不包含讀或寫資料的語句。

②NO SQL 表示子程式中不包含 SQL 語句。

③READS SQL DATA 表示子程式中包含讀資料的語句。

④MODIFIES SQL DATA 表示子程式中包含寫資料的語句。

⑤SQL SECURITY { DEFINER |INVOKER } 指明誰有權限來執行。

⑥DEFINER 表示隻有定義者自己才能夠執行。

⑦INVOKER 表示調用者可以執行。

⑧COMMENT ‘string’ 表示注釋資訊。

8.7存儲過程調用

8.8存儲函數

和存儲過程一樣,都是在資料庫中定義一些 SQL 語句的集合。存儲函數可以通過 return 語句傳回函數值,主要用于計算并傳回一個值。而存儲過程沒有直接傳回值,主要用于執行操作。

8.1.8.1文法在 MySQL 中,使用 CREATE FUNCTION 語句來建立存儲函數,其文法形式如下:
CREATE FUNCTION sp_name ([func_parameter[...]])
RETURNS type
[characteristic ...] routine_body
           

其中:

①sp_name 參數:表示存儲函數的名稱;

②func_parameter:表示存儲函數的參數清單;

③RETURNS type:指定傳回值的類型;

④characteristic 參數:指定存儲函數的特性,該參數的取值與存儲過程是一樣的;

⑤routine_body 參數:表示 SQL 代碼的内容,可以用 BEGIN…END 來标示 SQL 代碼的開始和結束。

**注意:**在具體建立函數時,函數名不能與已經存在的函數名重名。除了上述要求外,推薦函數名命名(辨別符)為 function_xxx 或者 func_xxx。

func_parameter 可以由多個參數組成,其中每個參數由參數名稱和參數類型組成,其形式如下:

[IN | OUT | INOUT] param_name type;

其中:

①IN 表示輸入參數,OUT 表示輸出參數,INOUT 表示既可以輸入也可以輸出;

②param_name 參數是存儲函數的參數名稱;

③type 參數指定存儲函數的參數類型,該類型可以是 MySQL 資料庫的任意資料類型。

8.8.2例子

Delimiter $$;
 create function real_income(employeeID_1 varchar(6),employeeID_2 varchar(6)) returns tinyint(1) begin if (select income - outcome from salary where employeeID=employeeID_1) >  (select income - outcome from salary where employeeID=employeeID_2) then return 0; else return 1;  end if ;  end$$
           

8.9定義變量

MySQL 中可以使用 DECLARE 關鍵字來定義變量,其基本文法如下:

DECLARE var_name[,…] type [DEFAULT value]

其中:

  • DECLARE 關鍵字是用來聲明變量的;
  • var_name 參數是變量的名稱,這裡可以同時定義多個變量;
  • type 參數用來指定變量的類型;
  • DEFAULT value 子句将變量預設值設定為 value,沒有使用 DEFAULT 子句時,預設值為 NULL。

8.9.1例 1

下面定義變量 my_sql,資料類型為 INT 類型,預設值為 10。SQL 語句如下:

8.9.2. 為變量指派

MySQL 中可以使用 SET 關鍵字來為變量指派,SET 語句的基本文法如下:

SET var_name = expr[,var_name = expr]...
           

其中:

  • SET 關鍵字用來為變量指派;
  • var_name 參數是變量的名稱;
  • expr 參數是指派表達式。

注意:一個 SET 語句可以同時為多個變量指派,各個變量的指派語句之間用逗号隔開。

8.9.3例 2

下面為變量 my_sql 指派為 30。SQL 語句如下:

MySQL 中還可以使用 SELECT…INTO 語句為變量指派。其基本文法如下:

SELECT col_name [...] INTO var_name[,...]
FROM table_name WEHRE condition
           

其中:

  • col_name 參數表示查詢的字段名稱;
  • var_name 參數是變量的名稱;
  • table_name 參數指表的名稱;
  • condition 參數指查詢條件。

注意:當将查詢結果指派給變量時,該查詢語句的傳回結果隻能是單行。

8.10例子

8.10.1.建立一個存儲過程執行個體

mysql> delimiter $$

mysql> create procedure show_employeeInfo()

  -> begin

  -> select *from employee;

  -> end$$

Query OK, 0 rows affected (0.49 sec)
           
MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗

然後檢視過程存儲建立結構:

MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗

最後調用存儲過程函數:

MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗

8.10.2.删除存儲過程:使用DROP PROCEDURE語句删除存儲過程,文法格式為:

MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗
DROP PROCEDURE [IF EXISTS] 存儲過程名;
           

8.10.3建立一個存儲過程,計算employee表中的員勞工數,并存儲到一個局部變量中,調用存儲過程,并檢視該變量結果(使用select @variable)

create procedure count_employee(out count_emp int)  begin set count_emp = (select count(*) from employee) ;  end $$ 
           
MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗
MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗
MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗

調用并查詢結果:

8.10.4.建立一個存儲過程,比較兩個員工的實際收入,若前者比後者高就輸出0,否則輸出1,員工用其員工編号識别。

Delimiter $$;

 create function real_income(employeeID_1 varchar(6),employeeID_2 varchar(6)) returns tinyint(1) begin if (select income - outcome from salary where employeeID=employeeID_1) >  (select income - outcome from salary where employeeID=employeeID_2) then return 0; else return 1;  end if ;  end$$
           

這時出現報錯:

MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗

這是我們開啟了bin-log, 我們就必須指定我們的函數是否是

1 DETERMINISTIC 不确定的

2 NO SQL 沒有SQl語句,當然也不會修改資料

3 READS SQL DATA 隻是讀取資料,當然也不會修改資料

4 MODIFIES SQL DATA 要修改資料

5 CONTAINS SQL 包含了SQL語句

其中在function裡面,隻有 DETERMINISTIC, NO SQL 和 READS SQL DATA 被支援。如果我們開啟了 bin-log, 我們就必須為我們的function指定一個參數。

在MySQL中建立函數時出現這種錯誤的解決方法:

set global log_bin_trust_function_creators=TRUE;

MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗

問題解決。

然後開始調用函數:

MYSQL學習與資料庫綜合實驗(八)——存儲過程實驗

成功實作需要的功能。

8.11詳細的實驗資料以及指導PPT請通路筆者GitHub位址:https://github.com/LJF2402901363/database_experiment.git

8.12本部落格已經同步到個人部落格,如有需要請移步:http://moyisuiying.com/index.php/experiment/mysqlexperiment/380.html

繼續閱讀