深入学习存储过程


介绍

优点

存储过程可封装,并隐藏复杂的商业逻辑。
存储过程可以回传值,并可以接受参数。
存储过程无法使用 SELECT 指令来运行,因为它是子程序,与查看表,数据表或用户定义函数不同。
存储过程可以用在数据检验,强制实行商业逻辑等。

缺点

存储过程,往往定制化于特定的数据库上,因为支持的编程语言不同。当切换到其他厂商的数据库系统时,需要重写原有的存储过程。
存储过程的性能调校与撰写,受限于各种数据库系统。


存储过程中的关键语法

声明语句结束符,可以自定义。

DELIMITER $$
或
DELIMITER //

声明存储过程

CREATE PROCEDURE demo_in_parameter(IN p_in int)       

存储过程开始和结束符号

BEGIN .... END   

变量赋值

局部变量用一个@标识,全局变量用两个@(常用的全局变量一般都是已经定义好的);

申明局部变量语法:declare @变量名 数据类型;例如:declare @num int;

赋值:有两种方法式(@num为变量名,value为值)

set @num=value; 或 select @num=value;

如果想获取查询语句中的一个字段值可以用select给变量赋值,如下:

select @num=字段名 from 表名 where ……

mysql中变量不用事前申明,在用的时候直接用“@变量名”使用就可以了。

第一种用法:set @num=1; 或set @num:=1; //这里要使用变量来保存数据,直接使用@num变量

第二种用法:select @num:=1; 或 select @num:=字段名 from 表名 where ……

注意上面两种赋值符号,使用set时可以用“=”或“:=”,但是使用select时必须用“:=赋值”

SET @p_in=1  

变量定义

DECLARE l_int int unsigned default 4000000; 

创建mysql存储过程、存储函数

create procedure 存储过程名(参数)

存储过程体

create function 存储函数名(参数)

举例说明

存储过程的例子

delimiter $$  #将语句的结束符号从分号;临时改为两个$$(可以是自定义)
create procedure sb1(in userid integer)   #输入userid的类型为integer,该函数名字为sb1
begin
delete from t_user where id = userid;   #删除t_user表id为userid的用户
end $$
delimiter ;    #将语句的结束符号恢复为分号

在这里插入图片描述

调用存储过程

call sp_name[(传参)];

call sb1(6);

存储过程的参数

IN 输入参数

表示调用者向过程传入值(传入值可以是字面量或变量)

delimiter $$  #将语句的结束符号从分号;临时改为两个$$(可以是自定义)
create procedure sb1(in userid integer)   #输入userid的类型为integer,该函数名字为sb1
begin
delete from t_user where id = userid;   #删除t_user表id为userid的用户
end $$
delimiter ;    #将语句的结束符号恢复为分号


set @s1 = 7;
call sb1(@s1);
mysql> delimiter $$
mysql> create procedure in_param(in p_in int)
    -> begin
    ->   select p_in;
    ->   set p_in=2;
    ->    select P_in;
    -> end$$
mysql> delimiter ;
 
mysql> set @p_in=1;
 
mysql> call in_param(@p_in);
+------+
| p_in |
+------+
|    1 |
+------+
 
+------+
| P_in |
+------+
|    2 |
+------+
 
mysql> select @p_in;
+-------+
| @p_in |
+-------+
|     1 |
+-------+

以上可以看出,p_in 在存储过程中被修改,但并不影响 @p_in 的值,因为前者为局部变量、后者为全局变量。

OUT 输出参数

表示过程向调用者传出值(可以返回多个值)(传出值只能是变量)

mysql> delimiter //
mysql> create procedure out_param(out p_out int)
    ->   begin
    ->     select p_out;
    ->     set p_out=2;
    ->     select p_out;
    ->   end
    -> //
mysql> delimiter ;
 
mysql> set @p_out=1;
 
mysql> call out_param(@p_out);
+-------+
| p_out |
+-------+
|  NULL |
+-------+
  #因为out是向调用者输出参数,不接收输入的参数,所以存储过程里的p_out为null
+-------+
| p_out |
+-------+
|     2 |
+-------+
 
mysql> select @p_out;
+--------+
| @p_out |
+--------+
|      2 |
+--------+
  #调用了out_param存储过程,输出参数,改变了p_out变量的值

INOUT 输入输出参数

既表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变量)

mysql> delimiter $$
mysql> create procedure inout_param(inout p_inout int)
    ->   begin
    ->     select p_inout;
    ->     set p_inout=2;
    ->     select p_inout;
    ->   end
    -> $$
mysql> delimiter ;
 
mysql> set @p_inout=1;
 
mysql> call inout_param(@p_inout);
+---------+
| p_inout |
+---------+
|       1 |
+---------+
 
+---------+
| p_inout |
+---------+
|       2 |
+---------+
 
mysql> select @p_inout;
+----------+
| @p_inout |
+----------+
|        2 |
+----------+
#调用了inout_param存储过程,接受了输入的参数,也输出参数,改变了变量

注意:

1、如果过程没有参数,也必须在过程名后面写上小括号例:

CREATE PROCEDURE sp_name ([proc_parameter[,...]]) ……

2、确保参数的名字不等于列的名字,否则在过程体中,参数名被当做列名来处理

建议:

输入值使用in参数。
返回值使用out参数。
inout参数就尽量的少用。

变量

局部变量声明一定要放在存储过程体的开始:

DECLAREvariable_name [,variable_name...] datatype [DEFAULT value];

其中,datatype 为 MySQL 的数据类型,如: int, float, date,varchar(length)

例如:

DECLARE l_int int unsigned default 4000000;  
DECLARE l_numeric number(8,2) DEFAULT 9.95;  
DECLARE l_date date DEFAULT '1999-12-31';  
DECLARE l_datetime datetime DEFAULT '1999-12-31 23:59:59';  
DECLARE l_varchar varchar(255) DEFAULT 'This will not be padded';

变量赋值

SET 变量名 = 表达式值 [,variable_name = expression ...]

用户变量

mysql > SELECT 'Hello World' into @x;  
mysql > SELECT @x;  
+-------------+  
|   @x        |  
+-------------+  
| Hello World |  
+-------------+  
mysql > SET @y='Goodbye Cruel World';  
mysql > SELECT @y;  
+---------------------+  
|     @y              |  
+---------------------+  
| Goodbye Cruel World |  
+---------------------+  
 
mysql > SET @z=1+2+3;  
mysql > SELECT @z;  
+------+  
| @z   |  
+------+  
|  6   |  
+------+

MySQL存储过程的控制语句

变量作用域

内部的变量在其作用域范围内享有更高的优先权,当执行到 end。变量时,内部变量消失,此时已经在其作用域外,变量不再可见了,应为在存储过程外再也不能找到这个申明的变量,但是你可以通过 out 参数或者将其值指派给会话变量来保存其值。

mysql > DELIMITER //  
mysql > CREATE PROCEDURE proc3()  
     -> begin 
     -> declare x1 varchar(5) default 'outer';  
     -> begin 
     -> declare x1 varchar(5) default 'inner';  
      -> select x1;  
      -> end;  
       -> select x1;  
     -> end;  
     -> //  
mysql > DELIMITER ;

条件语句

if-then-else 语句

mysql > DELIMITER //  
mysql > CREATE PROCEDURE proc2(IN parameter int)  
     -> begin 
     -> declare var int;  
     -> set var=parameter+1;  
     -> if var=0 then 
     -> insert into t values(17);  
     -> end if;  
     -> if parameter=0 then 
     -> update t set s1=s1+1;  
     -> else 
     -> update t set s1=s1+2;  
     -> end if;  
     -> end;  
     -> //  
mysql > DELIMITER ;

case语句:

mysql > DELIMITER //  
mysql > CREATE PROCEDURE proc3 (in parameter int)  
     -> begin 
     -> declare var int;  
     -> set var=parameter+1;  
     -> case var  
     -> when 0 then   
     -> insert into t values(17);  
     -> when 1 then   
     -> insert into t values(18);  
     -> else   
     -> insert into t values(19);  
     -> end case;  
     -> end;  
     -> //  
mysql > DELIMITER ; 
case
    when var=0 then
        insert into t values(30);
    when var>0 then
    when var<0 then
    else
end case

循环语句

  1. while ···· end while
mysql > DELIMITER //  
mysql > CREATE PROCEDURE proc4()  
     -> begin 
     -> declare var int;  
     -> set var=0;  
     -> while var<6 do  
     -> insert into t values(var);  
     -> set var=var+1;  
     -> end while;  
     -> end;  
     -> //  
mysql > DELIMITER ;
while 条件 do
    --循环体
endwhile
  1. repeat···· end repeat

它在执行操作后检查结果,而 while 则是执行前进行检查。

mysql > DELIMITER //  
mysql > CREATE PROCEDURE proc5 ()  
     -> begin   
     -> declare v int;  
     -> set v=0;  
     -> repeat  
     -> insert into t values(v);  
     -> set v=v+1;  
     -> until v>=5  
     -> end repeat;  
     -> end;  
     -> //  
mysql > DELIMITER ;
repeat
    --循环体
until 循环条件  
end repeat;
  1. loop ·····endloop

loop 循环不需要初始条件,这点和 while 循环相似,同时和 repeat 循环一样不需要结束条件, leave 语句的意义是离开循环。

mysql > DELIMITER //  
mysql > CREATE PROCEDURE proc6 ()  
     -> begin 
     -> declare v int;  
     -> set v=0;  
     -> LOOP_LABLE:loop  
     -> insert into t values(v);  
     -> set v=v+1;  
     -> if v >=5 then 
     -> leave LOOP_LABLE;  
     -> end if;  
     -> end loop;  
     -> end;  
     -> //  
mysql > DELIMITER ;
  1. LABLES 标号:

标号可以用在 begin repeat while 或者 loop 语句前,语句标号只能在合法的语句前面使用。可以跳出循环,使运行指令达到复合语句的最后一步。

ITERATE迭代

ITERATE 通过引用复合语句的标号,来从新开始复合语句:

mysql > DELIMITER //  
mysql > CREATE PROCEDURE proc10 ()  
     -> 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 t values(v);  
     -> set v=v+1;  
     -> if v>=5 then 
     -> leave LOOP_LABLE;  
     -> end if;  
     -> end loop;  
     -> end;  
     -> //  
mysql > DELIMITER ;

存储过程实现加减乘除

相加

USE shop;

delimiter $
CREATE PROCEDURE addNum ( IN a INT, IN b INT ) BEGIN
	DECLARE
		res INT DEFAULT 0;
	IF
		a IS NULL THEN
			
			SET a = 0;
		
	END IF;
	IF
		b IS NULL THEN
			
			SET b = 0;
		
	END IF;
/* a+b */
	
	SET res = a + b;
/* output the result */
	SELECT
		res;
	
END;
$delimiter;

相减

USE shop;

delimiter $
CREATE PROCEDURE subNum ( IN a INT, IN b INT ) BEGIN
	DECLARE
		res INT DEFAULT 0;
	IF
		a IS NULL THEN
			
			SET a = 0;
		
	END IF;
	IF
		b IS NULL THEN
			
			SET b = 0;
		
	END IF;
/* a-b */
	
	SET res = a - b;
/* output the result */
	SELECT
		res;
	
END;
$delimiter;

相乘

USE shop;

delimiter $
CREATE PROCEDURE multiNum ( IN a INT, IN b INT ) BEGIN
	DECLARE
		res INT DEFAULT 0;
	IF
		a IS NULL THEN
			
			SET a = 0;
		
	END IF;
	IF
		b IS NULL THEN
			
			SET b = 0;
		
	END IF;
/* a*b */
	
	SET res = a * b;
/* output the result */
	SELECT
		res;
	
END;
$delimiter;

相除

USE shop;

delimiter $
CREATE PROCEDURE divNum ( IN a INT, IN b INT ) BEGIN
/* res is float */
	DECLARE
		res FLOAT DEFAULT 0;
	IF
		a IS NULL THEN
			
			SET a = 0;
		
	END IF;
	IF
		b IS NULL THEN
			
			SET b = 0;
		
	END IF;
/* a/b */
	IF
		b = 0 THEN
			
			SET res = NULL;
		ELSE 
			SET res = a / b;
		
	END IF;
/* output the result */
	SELECT
		res;
	
END;
$delimiter;

调用其中一个存储过程案例

在这里插入图片描述

其他

MySQL存储过程的调用

用call和你过程名以及一个括号,括号里面根据需要,加入参数,参数包括输入参数、输出参数、输入输出参数。具体的调用方法可以参看上面的例子。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

和烨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值