Mysql存储过程

学习MYSQL存储过程

转载自:http://www.jzxue.com/shujuku/mysql/200908/10-2477.html


 一、简介

    存储过程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 |
+------+------+--------+-------+--------+-------+-------+

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值