您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

学习MYSQL存储过程_MySQL

2024/3/20 23:31:32发布19次查看
一、 简介
    存储过程(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.00 sec)
2、存储函数
  create function 函数名 ([函数参数[,...]])
  returns 返回类型
  [特性 ...] 函数体
如创建:create function f1 (x int)
returns int
return x;       /* 过程函数一次只能返回一个值
调用一下:select f1 (3);
将显示:
+-------+
| f1(3) |
+-------+
|     3 |
+-------+
1 row in set (0.00 sec)
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” 类型参数。
对于任何声明为out或inout的参数,,当调用存储过程时需要在参数名前加上@符号,这样该参数就可以在过程外调用了。
 下面举三个实例:mysql 存储过程 “in” 参数:跟 c 语言的函数参数的值传递类似, mysql 存储过程内部可能会修改此参数,但对 in 类型参数的修改,对调用者(caller)来说是不可见的(not visible)。
create procedure pr_param_in(   in id int -- in 类型的 mysql 存储过程参数)begin   if (id is not null) then      set id = id + 1;   end if;    select id as id_inner;end;set @id = 10; call pr_param_in(@id); select @id as id_out;mysql> call pr_param_in(@id);+----------+| id_inner |+----------+|       11 |+----------+ mysql> select @id as id_out;+--------+| id_out |+--------+| 10     |+--------+可以看到:用户变量 @id 传入值为 10,执行存储过程后,在过程内部值为:11(id_inner),但外部变量值依旧为:10(id_out)。
mysql 存储过程 “out” 参数:从存储过程内部传值给调用者。在存储过程内部,该参数初始值为 null,无论调用者是否给存储过程参数设置值。
create procedure pr_param_out(   out id int)begin   select id as id_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;   end if;    select id as id_inner_3;end;set @id = 10; call pr_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 的初始值总是 null(id_inner_1)。最后 id 值(id_out = 1)传回给调用者。
mysql 存储过程 inout 参数跟 out 类似,都可以从存储过程内部传值给调用者。不同的是:调用者还可以通过 inout 参数传递值给存储过程。
drop procedure if exists pr_param_inout; create procedure pr_param_inout(   inout id int)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;   end if;    select id as id_inner_3;end;set @id = 10; call pr_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     |+--------+从结果可以看出:我们把 @id(10),传给存储过程后,存储过程最后又把计算结果值 11(id_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、执行存储例程
    执行存储例程一般是通过call和select语句来完成的。
    三、多语句存储例程
单语句存储例程非常有用,但存储例程的真正功能在于它能够封装和执行多个sql语句。
下面介绍创建多语句存储例程时常用的语法。
  1、begin和end
当创建多语句存储例程时,需要将语句包围在begin/end块中。
此块的原型如下:
begin
     statement 1;
     statement 2;
     ……
     statement n;
end
注意,块中每条语句必须以分号结尾。
 2、条件语句
˜ if-elseif-else语句
 和c语言中if语句相似。
其原型如下:
if condition1 then
statement1;
elseif condition2 then
statement2;
…….
end if
˜ case语句
需要比较一组可能的值时case语句很有用。也是一种条件判断语句。
其原型如下:
case
when condition1 then statement1;
when condition2 then statement2;
………
end case;
3、迭代
有些任务需要能够重复地执行一组语句。下面介绍能够迭代执行和退出循环的各种方法。
˜ iterate语句
执行iterate语句将使嵌入该语句的loop、repeat或while循环返回顶部,并在此执行。
其原型如下:
iterate  label
˜ leave语句
在得到变量的值或特定任务的结果后,可能希望通过leave命令立即退出循环或begin/end块。
其原型如下:
leave  label
˜ loop语句
loop语句将不断的迭代处理定义在其代码块中的一组语句,直到遇到leave为止。
其原型如下:
[begin_label:]  loop
   statement_list
end loop  [end_label]
      ˜ repeat语句
       repeat语句在操作上几乎与while相同,很想c语言中的do….where语句。
      其原型如下:
 repeat
       statement_list
 until condition
 end repeat
˜ while语句
 其原型如下:
  while condition do
    statement_list
        end while
下面写一个循环语句的存储过程:
delimiter $$
drop procedure if exists `yyw`.`p2` $$
create procedure `yyw`.`p2` ()
begin
        declare v int;
 set v=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;
 end loop;
end $$
delimiter ;
    四、从另一个例程中调用例程
delimiter //
create procedure  p1()
begin
   statement_list
end//
create procedure  p2()
begin
   statement_list
end//
create procedure  p3()
begin
   call  p1();
   call  p2();
end//
注意:直接采用mysql的administrator管理器编辑时,可以直接采用函数文本录入;
    但若在脚本中自动导入存储过程或函数时,由于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 $$
drop procedure if exists `yyw`.`p4` $$
create definer=`yang`@`10.10.19.161` procedure `p4`(a int,b int)
begin
   declare c int;             /*声明的变量
if a is null then            /*if语句  
      set a = 0;
   end if;
if b is null then
      set b = 0;
   end if;
set c = a + b;
select c as sum;          /*结果显示c的值
end $$
delimiter ;
调用以下:call  p4(3,4);
将显示:
+------+
| sum  |
+------+
|    7 |
+------+
1 row in set (0.00 sec)
(2)存储过程中的循环语句、数据表数据的导入导出及sql函数的使用
delimiter $$
drop procedure if exists `yyw`.`p4` $$
create definer=`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         set x=2;
         pp1:while x            if j%x=0 then               /*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 text2 values(j);    /*将j的值插入数据表text2*/
         end if;
           set j=j+1;            /*实现j的自增*/
      end while;
 end $$
delimiter ;
假如原先在数据库中分别建立表text1和text2,text1中有一个字段初始值为3,text2为空;
下面执行一下此存储过程:
mysql> call pro_prime2(5);
+--------+------+
| count  | j    |
+--------+------+
| count  |    3 |
+--------+------+
1 row in set (0.00 sec)
mysql> select *from text2;
+-------+
| yywid |
+-------+
|     3 |
|     5 |
|     7 |
|    11 |
|    13 |
+-------+
5 rows 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 a int;                  /*    变量的声明   */
                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,physis int,total int,aver decimal(        4,2));                     /*  建一个数据表以存放要显示的内容*/
                repeat                 /* 引进一个repeat循环,来计算每位学生总分及平均分*/
                select  enlish,maths,physis,name into a,b,c,f from chengjibiao where num=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 *from zongping;           /* 以数据表的形式显示运行结果*/
               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 |
+------+------+--------+-------+--------+-------+-------+
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product