MySQL中的存儲過程和函數



存儲過程和函數

  • 簡單的說,存儲過程就是一條或者多條SQL語句的集合。可以視為批文件,但是其作用不僅僅局限於批處理。本文主要介紹如何創建存儲過程和存儲函數,以及如何調用、查看、修改、刪除存儲過程和存儲函數等。
創建存儲過程和函數

  存儲程序分為存儲過程和存儲函數。Mysql創建存儲過程和存儲函數的語句分別為CREATE PROCEDURE和CREATE FUNCTION。使用CALL語句來調用存儲過程,只能用輸出變量返回值。存儲函數可以從語句外調用(通過引用函數名),也能返回標量值。存儲過程也可以調用其他存儲過程。廢話少說,如下步入正文。

  • 創建存儲過程

  創建存儲過程的基本語法格式為:CREATE PROCEDURE sp_name([proc_parameter]) [characteristics] routine_body

  其中CREATE PROCEDURE為創建存儲過程的關鍵字,sp_name為存儲過程的名稱,pro_parameter為指定存儲過程的參數列表,其中參數列表如下:

  1. [IN|OUT|INOUT] param_name type 其中,IN表述輸入參數,OUT表示輸出參數,INOUT表示即可輸入也可輸出;param_name表述參數名稱;type表示參數類型,該類型可以是MySQL數據庫中的任意類型。
  2. characteristics指定存儲過程的特性,有以下取值:
    • LANGUAGE SQL:說明routine_body部分是由SQL語句組成的,當前系統支持的語言為SQL,SQL是LANGUAGE特性的唯一值。
    • [NOT] DETERMINISTIC:指明存儲過程執行的結果是否確定。DETERMINISTIC表示結果是確定的,每次執行存儲過程時,相同的輸入會得到相同的輸出,NOT DETERMINISTIC表示結果是不確定的,相同的輸入可能得到不同的輸出,如果沒有指定任意一個值,默認為NOT DETERMINISTIC。
    • [CONTAINS SQL|NO SQL|READS SQL DATA|MODIFIES SQL DATA]:指明子程序使用SQL語句的限制。CONTAINS SQL表明子程序包含SQL語句,但不包含讀寫數據語句;NO SQL表明子程序不包含SQL語句;READS SQL DATA說明子程序包含讀數據的語句;MODIFIES SQL DATA表名子程序包含寫數據的語句。默認情況下,系統會指定為CONTAINS SQL。
    • SQL SECURITY[DEFINER|INVOKER]:指明誰有權限來執行。DEFINER表示只有定義着才能執行。INVOKER表示用友權限的調用者可以執行。默認情況下,系統指定為DEFINER。
    • COMMENT 'string':注釋信息,用來描述存儲過程或函數。
  3. routine_body是SQL代碼的內容,可以用BEGIN...END來表示SQL代碼的開始和結束。

  我們從最簡單的存儲過程開始說起,如下是不包含任何參數的存儲過程,代碼為:CREATE PROCEDURE Proc() BEGIN SELECT * FROM tb_score; END; 我們定義了一個名稱為Proc的存儲過程,該過程是用來查詢tb_score(該表接上篇博客,已存在)數據庫表中的所有數據。

         

   第一張圖是通過執行sql語句查詢到tb_score表中的數據。第二張圖是創建存儲過程,其中第一句DELIMITER //是將MySQL的結束符設置為//,因為MySQL默認的結束符為分號,為了避免與存儲過程中SQL語句結束符相沖突,需要DELIMITER改變存儲過程的結束符,並以“END //”結束存儲過程。第三張圖是調用存儲過程,在調用存儲過程之前先將MySQL結束符恢復為默認的分號(DELIMITER ;)然后通過CALL Proc()調用。

  接下來我們講解MySQL存儲過程中的參數IN、OUT、INOUT,IN作為輸入,將輸入作為參數傳輸到存儲過程的執行當中去;OUT作為輸出,將存儲過程的輸出通過參數傳出來,而INOUT參數可以同時作為輸入和輸出。

  還是通過存儲過程查詢tb_score表,不過這次我們要查詢課程號為1(cID=1)的所有學生的成績,存儲過程定義為:CREATE PROCEDURE Proc_cID(IN classID INT) BEGIN SELECT * FROM tb_score WHERE cID=classID; END;

    

  如我們需要查詢課程號為1的學生的人數和平均成績,則存儲過程定義如下:CREATE PROCEDURE Proc_AVG(IN classID INT,OUT total INT,OUT a_s FLOAT) BEGIN SELECT COUNT(*),AVG(grade) INTO total,a_s FROM tb_score WHERE cID=classID; END;

  • 創建存儲函數

  創建存儲函數需要使用CREATE FUNCTION語句,基本語法格式為:CREATE FUNCTION func_name([func_parameter]) returns type [characteristic] routine_body CREATE FUNCTION為用來創建存儲函數的關鍵字,func_name表示存儲函數的名稱,func_parameter為存儲過程的參數列表如下:

    • [IN|OUT|INOUT] param_name type 其參數含義同存儲過程(PROCEDURE)相同,其默認為IN參數。

  RETURNS type語句表示函數返回數據的類型,characteristic指定存儲函數的特性,取值與創建存儲過程時相同。

  查詢某個學生某門課程的成績函數代碼為:CREATE FUNCTION Query_score(classID INT,studentID INT) RETURNS INT RETURN (SELECT grade FROM tb_score WHERE cID=classID AND sID=studentID); 通過SELECT Query_score(1,1)查詢1號學生1號課程的成績。

 

  讀者可能會發現存儲過程的查詢結果可能為多個值,而存儲函數的查詢結果是某一類型的單值。而且存儲過程在調用時用CALL而存儲函數是SELECT。那么存儲過程和函數具體的區別又是什么呢?

  1. 存儲過程的功能更加復雜,而函數的功能針對性更強;
  2. 存儲過程可以返回參數(通過OUT|INOUT),而函數只能返回單一值或者表對象;
  3. 存儲過程作為一個獨立的部分來執行,而函數可以作為查詢語句的一部分來調用,由於函數可以返回一個表對象,因此它可以在查詢語句中位於FROM關鍵字之后;
  4. 存儲過程是通過關鍵字CALL來調用,作為一個獨立的執行部分。而存儲函數則可作為SELECT語句的一部分調用,嵌入到SQL語句中;
  5. 當存儲過程和函數被執行的時候,SQLManager會到procedure cache中去取相應的查詢語句,如果在procedure cache里沒有相應的查詢語句,SQLManager就會對存儲過程和函數進行編譯。
  • 變量的使用

  變量可以在子程序中聲明並使用,作用范圍是在BEGIN...END程序中,如下將主要介紹如何定義變量和為變量賦值。

  1. 定義變量。語法格式為:DECLARE var_name[,var_name]...data_type[DEFAULT value]; var_name為局部變量名稱,DEFAULT value給變量提供一個默認值。值除了可以被聲明為一個常數之外,還可以被指定為一個表達式。如果缺少DEFAULT子句,初始值為NULL。
  2. 為變量賦值。MySQL中使用SET語句為變量賦值,語法格式為:SET var_name=expr[,var_name=expr]...
  • 流程控制的使用

  流程控制與用來根據條件控制語句的執行。MySQL中的用來構造控制流程的語句有:IF語句、CASE語句、LOOP語句、LEAVE語句、ITERATE語句、REPEAT語句和WHILE語句。各語句介紹如下:

  1. IF語句。包含多個條件判斷,根據判斷的結果為TRUE或FALSE執行相應的語句,語法格式為 IF expr_condition THEN statement_list ESLEIF expr_condition THEN statement_list ESLE statement_list END IF 如下我們定義一個學生成績等級評定函數,將學生成績以參數的形式傳輸函數,輸出學生成績等級A(90~100)、B(75~90)、C(60~75)、D(60以下)。代碼編寫中需要注意,IF中如果有多個限制條件,限制條件間用AND連接,DECLARE的變量聲明必須在BEGIN內,以及字符串之間拼接用CONCAT。該功能代碼如下圖所示:
  2. CASE語句。另外一個進行條件判斷的語句,該語句有2種語句格式。
    1. 第一種格式為:CASE case_expr WHEN value THEN statement_list [WHEN value THEN statement_list] [ELSE statement_list] END CASE 其中case_expr參數表示條件判斷的表達式,決定哪個WHEN子句會被執行,value表示表達式可能的值,如果case_expr等於某個value,則執行相應value后的statement_list。
    2. 第二種格式為:CASE WHEN expr_condition THEN statement_list [WHEN expr_condition THEN statement_list] [ELSE statement_list] END CASE 其中expr_condition參數表示條件判斷語句,該格式下,WHEN語句將被逐個執行,直到某個expr_condition表達式為真,則這行對應THEN關鍵字后面的statement_list語句。如果沒有匹配,ELSE子句里的語句被執行。
  3. LOOP語句。循環語句用來重復執行某些語句,與IF和CASE相比,LOOP只是創建一個循環操作的過程,並不進行條件判斷。LOOP內的語句一直重復執行直到循環被退出。跳出循環過程使用LEAVE子句,LOOP語句基本格式為:[label] LOOP statement_list END LOOP[label] label表示LOOP語句的標注名稱,該參數可以省略,statement_list表示需要執行的語句。
  4. LEAVE語句。從LOOP語句的例子中可知LEAVE語句用來退出任何被標注的流程控制構造,LEAVE語句基本格式為:LEAVE label

  5. ITERATE語句。將執行順序轉到語句段開頭處,語句基本格式為:ITERATE lable ITERATE只可以出現在LOOP、REPEAT和WHILE語句內。ITERATE的意思為再次循環,label參數表示循環的標志。ITERATE語句必須跟在循環標志前面。例子中p1=0,如果p1的值小於10時,重復執行p1加1操作;p1大於等於10並且小於20時,打印消息'p1 is between 10 and 20';p1大於20時,退出循環。
  6. REPEAT語句。創建一個帶條件判斷的循環過程,每次語句執行完畢后,會對條件表達式進行判斷,表達式為真循環結束,否則重復執行循環中的語句。語句基本格式:[label]:REPEAT statement_list UNTIL expr_condition END REPEAT [label]

  7. WHILE語句。WHILE語句創建一個帶條件判斷的循環過程,與REPEAT不同,WHILE在執行語句時先對指定的表達式進行判斷,為真則執行循環內的語句,否則退出循環。語句基本格式:[label] WHILE expr_condition DO statement_list END WHILE [label]
查看存儲過程和函數

  MySQL中,用戶可以使用SHOW STATUS語句或SHOW CREATE語句來查看存儲過程和函數,也可以直接從系統的information_schema數據庫中查詢。本節將通過實例來介紹這3種方法。

  • SHOW STATUS語句查看存儲過程和函數的狀態,其基本語法為:SHOW{PROCEDURE|FUNCTION} STATUS [LIKE 'pattern'] 這個語句返回子程序的特征,如數據庫、名字、類型、創建者及創建和修改日期。如果沒有指定樣式,根據使用的語句,所有存儲程序或存儲函數的信息都被列出。PROCEDURE和FUNCTION分別表示查看存儲過程和函數,LIKE語句表示匹配存儲過程或函數的名稱。
  • SHOW CREATE查看存儲過程和函數語句格式為:SHOW CREATE {PROCEDURE|FUNCTION} sp_name 它返回一個可以來重新創建已命名子程序的確切字符串。PROCEDURE和FUNCTION分別表示查看存儲過程和函數,同樣也可是使用LIKE匹配。

  • 從information_schema.Routines表中查看存儲過程和函數的信息。MySQL中存儲過程和函數的信息存儲在information_schema數據庫的Routines表中。通過查詢該表的記錄查詢存儲過程和函數的信息。基本語法格式為:SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME='sp_name' 其中ROUTINE_NAME字段存儲的是存儲過程和函數的名稱,sp_name參數表述存儲過程或函數的名稱。

修改存儲過程和函數

  使用ALTER語句可以修改存儲過程或函數的特性,本節將介紹如何通過ALTER語句修改存儲過程和函數。語法格式為:ALTER {PROCEDURE|FUNCTION} sp_name [characteristic ...] 其中,sp_name參數表示存儲過程或函數的名稱,characteristic參數指定存儲函數的特性,可能的取值有:

  1. CONTAINS SQL表示子程序包含SQL語句,但是不包含讀或寫數據的語句;
  2. NO SQL表示子程序中不包含SQL語句;
  3. READES SQL DATA表示子程序中包含讀數據的語句;
  4. MODIFIES SQL DATA表示子程序中包含寫數據的語句;
  5. SQL SECURITY{DEFINER|INVOKER}指明誰有權限來執行;
  6. DEFINER表示只有定義着自己才能夠執行;
  7. INVOKER表示調用者可以執行;
  8. COMMENT 'string'表示注釋信息。

  修改存儲過程使用ALTER PROCEDURE語句,修改存儲函數使用ALTER FUNCTION語句。

 

刪除存儲過程

  刪除存儲過程和函數可以使用DROP語句,語法格式為:DROP {PROCEDURE|FUNCTION} [IF EXISTS] sp_name 這個語句被用來移除一個存儲過程或函數,sp_name為要移除的存儲過程或函數的名稱。IF EXISTS子句是一個MySQL的擴展,如果存儲過程或函數不存在,以防發生錯誤,產生一個用SHOW WARNINGS查看的警告。

 

  最后再說幾點值得大家注意的吧:

  1. 目前MySQL不支持對已存在的存儲過程代碼進行修改,如果必須修改,則先使用DROP語句刪除該存儲過程,再重新創建新的存儲過程;
  2. 存儲過程中包含用戶定義的SQL語句集合,也可是使用CALL語句調用存儲過程,但不能使用DROP刪除其他存儲過程;
  3. 在定義存儲過程參數列表時,應注意把參數名與數據庫表中的字段名區別開,否則會報錯。
  4. 如果存儲過程中需要傳入中文參數,這時需要在定義存儲過程的時候,在參數后加上character set gbk,不然調用存儲過程使用中文參數會出錯。如CREATE PROCEDURE userInfo(IN u_name VARCHAR(50) character set gbk, OUT u_age INT)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM