MYSQL存儲過程-例程與模塊

  學了SQL語言詳解這本書,對MYSQL例程與模塊有了一點認識,現在轉載一篇MYSQL存儲過程供大家學習。

 轉載:http://blog.csdn.net/zhuizhuziwo/article/details/7861121

  

 一、簡介

    存儲過程Stored Procedure)是一組爲了完成特定功能的SQL語句集,經編譯後存儲在數據庫中。用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象,任何一個設計良好的數據庫應用程序都應該用到存儲過程。

    雖然常用術語是存儲過程(stored procedure),但MySQL實際上實現了兩中類型,除了存儲過程外,還有存儲函數(stored routine,它們統稱爲存儲例程。

    二、基本格式
1
、存儲過程
  CREATE PROCEDURE 
過程名 ([過程參數[,...]])
  [
特性 ...] 過程體

如創建: CEATE PROCEDURE p1 (a INT)

SELECT a;

調用一下:CALL p1(8);  

將顯示:

+------+

|a    |

+------+

|   8 |

+------+

1 row in set (0.00sec)
2
、存儲函數
  CREATE FUNCTION 
函數名 ([函數參數[,...]])
  RETURNS 
返回類型
  [
特性 ...] 函數體

如創建:CREATE FUNCTION f1 (x INT)

RETURNS INT

RETURN x;      /* 過程函數一次只能返回一個值

調用一下:SELECT f1 (3);

將顯示:

+-------+

| f1(3) |

+-------+

|    3 |

+-------+

1 row in set (0.00sec)

3、過程參數
  [ IN | OUT | INOUT ] 
參數名參數類型
4
、函數參數
  
參數名參數類型
5
、返回類型
  
有效的MySQL數據類型即可
6
、過程體/函數體格式如下
BEGIN
有效的SQL語句
END

7、特性(一般不要求)
LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'

8、存儲過程中參數的IN,OUT,INOUT類型

    存儲過程可以接受輸入參數,並把參數返回給調用方。不過,對於每個參數,需要聲明其參數名、數據類型,還要指定此參數是用於向過程傳遞信息,還是從過程傳回信息,或是二者兼有。

    爲聲明參數的作用,使用如下3個關鍵字之一:

˜ IN :  IN參數只用來向過程傳遞信息,爲默認值。

 

˜ OUT : OUT參數只用來從過程傳回信息。

 

˜ INOUT  INOUT參數可以向過程傳遞信息,如果值改變,則可再從過程外調用。

如果僅僅想把數據傳給 MySQL存儲過程,那就使用“in”類型參數;如果僅僅從 MySQL存儲過程返回值,那就使用“out”類型參數;如果需要把數據傳給 MySQL存儲過程,還要經過一些計算後再傳回給我們,此時,要使用“inout”類型參數。

對於任何聲明爲OUTINOUT的參數,,當調用存儲過程時需要在參數名前加上@符號,這樣該參數就可以在過程外調用了。

 下面舉三個實例:MySQL存儲過程 “in” 參數:跟 C 語言的函數參數的值傳遞類似, MySQL存儲過程內部可能會修改此參數,但對 in類型參數的修改,對調用者(caller)來說是不可見的(not visible)。

create procedurepr_param_in(   in id int -- in類型的 MySQL 存儲過程參數)

begin  

 if (id is not null) then     

set id = id + 1;   

end if;   

 select id asid_inner;

end;

set @id = 10; 


call pr_param_in(@id); 

select @id asid_out;

mysql> call pr_param_in(@id);

+----------+| id_inner |+----------+|      11 |+----------+ 

mysql> select @id as id_out;+--------+| id_out |+--------+|10     |+--------+


可以看到:用戶變量 @id傳入值爲 10,執行存儲過程後,在過程內部值爲:11id_inner),但外部變量值依舊爲:10id_out)。

MySQL 存儲過程 “out”參數:從存儲過程內部傳值給調用者。在存儲過程內部,該參數初始值爲 null,無論調用者是否給存儲過程參數設置值。

create procedurepr_param_out(   out id int)begin   select id asid_inner_1;    /* id初始值爲null*/    if (id is not null)then          set id = id +1;       select id as id_inner_2;  else      select 1 into id;   endif;    select id as id_inner_3;end;set @id = 10; callpr_param_out(@id); select @id as id_out;mysql> set @id =10;mysql>mysql> call pr_param_out(@id);    /*外部變量不能傳給存儲過程*/+------------+| id_inner_1|+------------+|       NULL |+------------++------------+| id_inner_3|+------------+|          1|+------------+ mysql> select @id as id_out;  /*過程將改變的值傳給外部變量*/+--------+| id_out |+--------+|1      |+--------+可以看出,雖然我們設置了用戶定義變量 @id 10,傳遞 @id給存儲過程後,在存儲過程內部,id的初始值總是 nullid_inner_1)。最後 id值(id_out = 1)傳回給調用者。

MySQL 存儲過程 inout參數跟 out 類似,都可以從存儲過程內部傳值給調用者。不同的是:調用者還可以通過 inout參數傳遞值給存儲過程。

drop procedure ifexists pr_param_inout; create procedure pr_param_inout(   inout idint)begin   select id as id_inner_1;  -- id值爲調用者傳進來的值   

 if (id is not null)then      set id = id +1;       

select id as id_inner_2;  else      select 1 into id;  

 endif;    select id as id_inner_3;end;

set @id = 10; callpr_param_inout(@id);

 select @id as id_out;mysql> set @id = 10;

mysql>mysql> call pr_param_inout(@id);+------------+| id_inner_1|+------------+|         10 |+------------++------------+| id_inner_2 |+------------+|        11 |+------------+ +------------+| id_inner_3|+------------+|         11|+------------+mysql>mysql> select @id as id_out;+--------+| id_out|+--------+| 11     |+--------+從結果可以看出:我們把 @id10),傳給存儲過程後,存儲過程最後又把計算結果值11id_inner_3)傳回給調用者。 MySQL存儲過程 inout 參數的行爲跟 C 語言函數中的引用傳值類似。

通過以上例子:如果僅僅想把數據傳給 MySQL存儲過程,那就使用“in”類型參數;如果僅僅從 MySQL存儲過程返回值,那就使用“out”類型參數;如果需要把數據傳給 MySQL存儲過程,還要經過一些計算後再傳回給我們,此時,要使用“inout”類型參數。

9、聲明和設置變量

1聲明變量

   在存儲例程使用局部變量之前,必須聲明局部變量,變量聲明通過DECLARE語句實現,其原型如下:

  DECLARE variable_name TYPE ;

如:DECLARE x VARCHAR(254);

   在聲明變量時,聲明必須放在BEGIN/END塊中。此外聲明必須在執行該塊任何其它語句之前進行。

2設置變量

SET語句用來設置聲明的存儲例程變量值。其原型如下:

SET  variable_name=value;

如下聲明和設置變量過程:

 DECLARE  x  INT;

SET  x = 155;

也可使用SELECT…..INTO語句設置變量。

  如:

SELECT 155  INTO  x;

當然,此變量是聲明該變量的BEGIN/END塊作用範圍內的一個局部變量。如果希望在存儲例程外使用此變量,需要將其作爲OUT變量傳遞。

 

10、執行存儲例程

   執行存儲例程一般是通過CALLSELECT語句來完成的。

   三、多語句存儲例程

單語句存儲例程非常有用,但存儲例程的真正功能在於它能夠封裝和執行多個SQL語句。

下面介紹創建多語句存儲例程時常用的語法。

 1BEGINEND

當創建多語句存儲例程時,需要將語句包圍在BEGIN/END塊中。

此塊的原型如下:

BEGIN

    statement 1;

    statement 2;

    ……

    statement N;

END

注意,塊中每條語句必須以分號結尾。

 2、條件語句

˜IF-ELSEIF-ELSE語句

 C語言中if語句相似。

其原型如下:

IFcondition1 THEN

statement1;

ELSEIFcondition2 THEN

Statement2;

…….

ENDIF

˜CASE語句

需要比較一組可能的值時CASE語句很有用。也是一種條件判斷語句。

其原型如下:

CASE

WHENcondition1 THEN statement1;

WHENcondition2 THEN statement2;

………

ENDCASE;

3、迭代

有些任務需要能夠重複地執行一組語句。下面介紹能夠迭代執行和退出循環的各種方法。

˜ITERATE語句

執行ITERATE語句將使嵌入該語句的LOOPREPEATWHILE循環返回頂部,並在此執行。

其原型如下:

ITERATE label

˜LEAVE語句

在得到變量的值或特定任務的結果後,可能希望通過LEAVE命令立即退出循環或BEGIN/END塊。

其原型如下:

LEAVE label

˜LOOP語句

LOOP語句將不斷的迭代處理定義在其代碼塊中的一組語句,直到遇到LEAVE爲止。

其原型如下:

[begin_label:] LOOP

  Statement_list

ENDLOOP  [end_label]

     ˜ REPEAT語句

      REPEAT語句在操作上幾乎與WHILE相同,很想C語言中的DO….WHERE語句。

     其原型如下:

 REPEAT

      Statement_list

 UNTILcondition

 ENDREPEAT

˜WHILE語句

 其原型如下:

 WHILE condition DO

   Statement_list

       END WHILE

下面寫一個循環語句的存儲過程:

DELIMITER$$

 

DROPPROCEDURE IF EXISTS `yyw`.`p2` $$

CREATEPROCEDURE `yyw`.`p2` ()

BEGIN

       declare v int;

 setv=0;

 LOOP_LABLE:loop

         if v=3 then

     set v=v+1;

     ITERATE LOOP_LABLE;

  end if;

  insert into vs values(v);         /*將循環值插入數據表vs*/

  set v=v+1;

  if v>=5 then

    leave LOOP_LABLE;

  end if;

 endloop;

END$$

 

DELIMITER;

   四、從另一個例程中調用例程

DELIMITER//

CREATEPROCEDURE  p1()

BEGIN

  Statement_list

END//

CREATEPROCEDURE  p2()

BEGIN

  Statement_list

END//

CREATEPROCEDURE  p3()

BEGIN

  CALL  p1();

  CALL  p2();

END//

 

注意:直接採用MySQLAdministrator管理器編輯時,可以直接採用函數文本錄入;
    
但若在腳本中自動導入存儲過程或函數時,由於MySQL默認以";"爲分隔符,則過程體的每一句都被MySQL以存儲過程編譯,則編譯過程會報錯;所以要事先用DELIMITER關鍵字申明當前段分隔符
用完了就把分隔符還原。如下所示:
DELIMITER 
$$
Stored Procedures and Functions
DELIMITER ;

   五、刪除和查看存儲例程

1、刪除存儲例程

要刪除存儲例程,可以執行DROP語句。

其原型如下:

 DROP (PROCEDURE|FUNCTION)  P_name;

  2、查看例程狀態

其原型如下:

SHOW (PROCEDURE|FUNCTION)  STATUS  LIKE  ‘P_name’

如:

SHOW PROCEDURE  STATUS  LIKE  ‘P3’\G

注意:使用\G選項以垂直格式顯示輸出信息。

  3、查看例程的創建語法

  通過SHOW CREATE語句可以查看創建特定例程所用的語法。

  其原型如下;

     SHOW CREATE  (PROCEDURE|FUNCTION)  Db_name.P_name

   六、實例

  一般在MySQL Query Browser中更方便的創建存儲過程及修改內容。

 

1)簡單的加法運算

DELIMITER$$

 

DROPPROCEDURE IF EXISTS `yyw`.`p4` $$

CREATEDEFINER=`yang`@`10.10.19.161` PROCEDURE `p4`(a int,b int)

BEGIN

  declare cint;             /*聲明的變量

if ais null then           /*IF語句  

     set a = 0;

  end if;

if bis null then

     set b = 0;

  end if;

set c= a + b;

selectc as sum;          /*結果顯示c的值

 

END$$

 

DELIMITER;

調用以下:CALL  p4(3,4);

將顯示:

+------+

|sum  |

+------+

|   7 |

+------+

1 rowin set (0.00 sec)

2)存儲過程中的循環語句、數據表數據的導入導出及SQL函數的使用

DELIMITER$$

 

DROPPROCEDURE IF EXISTS `yyw`.`p4` $$

CREATEDEFINER=`yang`@`10.10.19.161` PROCEDURE ‘pro_prime2’(in num int)

BEGIN

 declare i,j,x,y int default 0;    /*聲明變量並默認爲0*/
      select  yywID into j from text1;  /*
從數據表txte1中字段yywID的值賦給變量j*/
      select 'count',j;           /*
顯示count字符和j的值*/
      while i<numdo          /*while……do
循環語句*/
         set x=2;
         pp1:while x<=sqrt(j)do    /*
調用內部函數SQRT用於求平方*/
            if j%x=0then              /*if
循環語句*/
              set y=1;
              leave pp1;
            else
              set x=x+1;
            end if;
         end while;
         if y=1 then
           set y=0;
         else
           set i=i+1;
           insert into text2values(j);    /*
j的值插入數據表text2*/
         end if;
           setj=j+1;            /*
實現j的自增*/
      end while;
 END $$

 

DELIMITER;

假如原先在數據庫中分別建立表text1text2text1中有一個字段初始值爲3text2爲空;

下面執行一下此存儲過程:

mysql>CALL pro_prime2(5);

+--------+------+

|count  | j    |

+--------+------+

|count  |    3 |

+--------+------+

1 rowin set (0.00 sec)

mysql>select *from text2;

+-------+

|yywID |

+-------+

|    3 |

|    5 |

|    7 |

|   11 |

|   13 |

+-------+

5rows in set (0.00 sec)

 

3)用存儲過程實現計算數據庫中某個成績表總分及平均分,並且調用過程後

能夠自動顯示基本信息(如學號、姓名、總分、平均分等)。

   首先在數據庫中建一個成績表(命名爲chengjibiao)如下:

+-----+------+--------+-------+--------+
| NUM | Name | Enlish | Maths | Physis |
+-----+------+--------+-------+--------+
|   1 | 
楊業 |92     | 87    | 96    |
|   2 | 
劍鋒 |82     | 98    | 93    |
|   3 | 
張美 |96     | 86    | 94    |
|   4 | 
張文 |76     | 99    | 95    |
|   5 | 
葉倩 |97     | 86    | 88    |
|   6 | 
方文 |87     | 96    | 94    |
|   7 | 
李麗 |97     | 86    | 83    |
|   8 | 
賈宇 |67     | 89    | 77    |
|   9 | 
王勃 |89     | 67    | 75    |
|  10 | 
劉三 |85     | 78    | 95    |
+-----+------+--------+-------+--------+

 

 ‚SQL語句寫存儲過程p1    

                DELIMITER $$

                                                

               DROP PROCEDURE IF EXISTS `yyw`.`p1` $$

               CREATE DEFINER=`yang`@`10.10.19.161` PROCEDURE `p1`(N int)

               BEGIN

               declare aint;                 /*   變量的聲明   */

               declare b int;

               declare c int;

               declare d int;

               declare e int;

               declare f char(100);

               declare g decimal(4,2);

               set e=1;

               create table zongping (NUM int,Name char(255),Enlish int,Maths int,Physisint,Total int,aver decimal(       4,2));                    /* 建一個數據表以存放要顯示的內容*/

               repeat                /*引進一個REPEAT循環,來計算每位學生總分及平均分*/

               select  Enlish,Maths,Physis,Name into a,b,c,f from chengjibiao whereNUM=e;

                      /* 導出數據庫chengjibiao中的三門成績及姓名,並把它們分別賦給變量a,b,c,f;*/

               set d=a+b+c;         /*求和*/

               set g=(a+b+c)/3;      /*求平均分*/

               insert into zongping (NUM,Name,Enlish,Maths,Physis,Total,aver) values(e,f,a,b,c,d,g);

                /*將學號,姓名,三門成績,總分,平均分的數據插入新建的數據表zongping

               set e=e+1;       /*該條件可結束循環*/

               until e=N      /*N是調用存儲過程時根據學生數目來設定的*/

               end repeat;

               select *fromzongping;           /*以數據表的形式顯示運行結果*/

              drop table zongping;          /*顯示結果後刪除表,也可不刪*/

              END $$

                                  

              DELIMITER ;

                             

 l 調用存儲過程

              CALL  P1 (11);          /*因爲原成績表中有10列數據,故設N=11,也可根據不同的成績表另設

                            

      顯示結果如下:

  +------+------+--------+-------+--------+-------+

 |Name | Enlish | Maths | Physis | Total | Aver  |
+------+------+--------+-------+--------+-------+-------+
|    1 | 
楊業|     92 |    87 |    96 |   275 | 91.67 |
|    2 | 
劍鋒|     82 |    98 |    93 |   273 | 91.00 |
|    3 | 
張美|     96 |    86 |    94 |   276 | 92.00 |
|    4 | 
姜文|     76 |    99 |    95 |   270 | 90.00 |
|    5 | 
葉倩|     97 |    86 |    88 |   271 | 90.33 |
|    6 | 
方文|     87 |    96 |    94 |   277 | 92.33 |
|    7 | 
李麗|     97 |    86 |    83 |   266 | 88.67 |
|    8 | 
賈宇|     67 |    89 |    77 |   233 | 77.67 |
|    9 | 
王勃|     89 |    67 |    75 |   231 | 77.00 |
|   10 | 
劉三|     85 |    78 |    95 |   258 | 86.00 |
+------+------+--------+-------+--------+-------+-------+

發佈了25 篇原創文章 · 獲贊 10 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章