存储过程(Stored Procedure)

(一) 存储过程概述

1.定义:

​ 存储过程是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。在数据量特别庞大的情况下利用存储过程能达到倍速的效率提升。

2.优点:

  • 存储过程可封装,并隐藏复杂的业务逻辑
  • 存储过程可以回传值,并可以接受参数
  • 存储过程无法使用select语句运行,因为他是子程序
  • 存储过程可以用于数据检验,强制实行业务逻辑等

3.缺点

  • 存储过程用在特定的数据库上,因为支持的编程语言不通,当切换数据库时需要重新编写存储过程
  • 存储过程的性能调校与撰写,受限于不同的数据库系统

(二)存储过程的创建和调用

创建存储过程

I.主要语法:

(1)声明语句结束符

DELIMITER $$
或
DELIMITER //

(2)声明存储过程

CREATE PROCEDURE demo_in_parameter(IN p_in int)

(3)存储过程开始和结束的符号

BEGIN .... END

(4)给变量赋值

SET @p_in=1

(5)定义一个变量

DECLARE l_int int unsigned default 4000000;

(6)mysql创建存储过程,存储函数

create procedure 存储过程名(参数)

(7)存储过程体

create function 存储函数名(参数)

II.实例

已存在表users:

select * from users;
+---------+--------+----------+
|    id   |  name  |  address |
+---------+--------+----------+
|       1 |      a |      aaa |
|       2 |      b |      bbb |
|       3 |      c |      ccc |
+---------+--------+----------+

编写存储过程:

CREATE PROCEDURE delete_user(IN user_id INTEGER)
BEGIN
	DELETE FROM users
	WHERE id = user_id;
END;

调用存储过程delete_user,传入参数user_id = 3:

call delete_user(3);

再次查看表users:

select * from users;
+---------+--------+----------+
|    id   |  name  |  address |
+---------+--------+----------+
|       1 |      a |      aaa |
|       2 |      b |      bbb |
+---------+--------+----------+

III.存储过程体

  • 包含了在过程调用时必须执行的语句,例如dml语句(Data Manipulation Language,数据操纵语言),ddl语句(Data Definition Languages,数据定义语言),if-then-else,while-do语句,声明变量的declare语句等
  • 过程体格式:以begin开始,以end结束,可以嵌套
BEGIN
	BEGIN
		BEGIN
			statements;
		END
	END
END

每个嵌套块及其中的每条语句,必须以分号结束,表示过程体结束的begin-end块不需要分号

# 标签格式:
[begin_lable:]BEGIN
	[statement_list]
END[end_lable]

# 例如:
lable1: BEGIN
	lable2: BEGIN
		lable3: BEGIN
			statements;
		END lable3;
	END lable2;
END lable1;

标签的优点:

  1. 增强代码可读性
  2. 某些语句需要用到标签

(三)存储过程的参数

mysql存储类型参数有三种类型,定义格式如下:

CREATE PROCEDURE 存储过程名([[IN | OUT | INOUT] 参数名 参数类型...])
  • IN 输入参数:表示调用者向过程传入值(传入值可以是字面量或变量)
  • OUT 输出参数:表示过程向调用者传出值(可以返回多个值)(传出值只能是变量)
  • INOUT 输入输出参数:既表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变量)

I.in传入参数

CREATE PROCEDURE in_param(in p_in int)
begin
	select p_in;
	# 给变量p_in赋值(局部变量)
	set p_in=2;
	select p_in;
end;
# 给变量p_in赋值(全局变量)
set @p_in=1;
# 调用存储过程
call in_param(@p_in);
+------+     
| p_in |
+------+
|    1 |
+------+

+------+
| P_in |
+------+
|    2 |
+------+

# p_in在存储过程中被修改,但不影响@p_in的值,因为存储过程中为局部变量
select @p_in;
+-------+     
| @p_in |
+-------+
|     1 |
+-------+

II.out输出参数

CREATE PROCEDURE out_param(out p_out int)
begin
	select p_out;
	set p_out=2;
	select p_out;
end
set @p_out=1;
call out_param(@p_out);
+-------+
| p_out |
+-------+
|  NULL |
+-------+
# 因为out是向调用者输出参数,不接收输入的参数,所以存储过程里的p_out为null
+-------+
| p_out |
+-------+
|     2 |
+-------+

select @p_out
# 调用了out_param存储过程,输出参数,改变了p_out变量的值
+--------+
| @p_out |
+--------+
|      2 |
+--------+

III.inout输入参数

CREATE PROCEDURE inout_param(inout p_inout int)
begin
	select p_inout;
	set p_inout=2;
	select p_inout;
end
set @p_inout = 1;
call inout_param(@p_inout);
+---------+
| p_inout |
+---------+
|       1 |
+---------+
 
+---------+
| p_inout |
+---------+
|       2 |
+---------+
select @p_inout;
# 调用了inout_param存储过程,接受了输入的参数,也输出参数,改变了变量
+----------+
| @p_inout |
+----------+
|        2 |
+----------+
  • 确保村属名字不等于列名,否则在过程体中,被当作列名处理
  • 如果过程中没有参数,也必须在过程名后面写小括号
  • 传入值使用in,返回值使用out,尽量少用inout

(四)变量

I.变量定义

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

DECLARE variable_name [,variable_name...] datatype [DEFAULT value];
# datatype为mysql数据类型,例如:int, float, varchar, date....

例如:

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';

II.变量赋值

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

III.用户变量

select 'hello world' into @x;

select @x;
+-------------+  
|   @x        |  
+-------------+  
| hello world |  
+-------------+  

set @y='hello'
+-------+  
|   @y  |  
+-------+  
| hello |  
+-------+  

set @z=1+2+3;
select @z;
+------+  
| @z   |  
+------+  
|  6   |  
+------+

IV.在存储过程中使用用户变量

CREATE PROCEDURE Hello() select concat(@hello, 'world');
set @hello='hello';
call Hello();
+------------------------+  
| CONCAT(@hello,'world') |  
+------------------------+  
|  hello world           |  
+------------------------+

(五)存储过程的其他使用

  • 存储过程的查询
select * from mysql.proc where db='数据库名'
#查看单个存储过程的详细信息
show create procedure study.delete_user;
  • 存储过程的修改
ALTER PROCEDURE
  • 存储过程的删除
DROP PROCEDURE 存储过程名
  • 存储过程的控制语句

1.if-then-else语句

create procedure proc(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;

2.case语句

create procedure proc(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;
case
	when var=0 then
		insert into t values(30);
	when var>0 then
	when var<0 then
	else
end case

3.循环语句

# while 条件 do
#		--循环体
# end while
create procedure proc()
begin
	declare var int;
	set var=0;
	while var < 6 do
		insert into t values(var);
		set var=var+1;
	end while;
end;
# repeat .... end repeat
create procedure proc()
begin
	declare v int;
	set v=0;
	repeat
		insert into t values(v);
		set v=v+1;
	until v>=5
	end repeat;
end;
# loop .... end loop
create procedure proc()
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;

4.ITERATE迭代

create procedure proc()
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;

(六)存储过程的使用场景

当一个事务涉及到多个SQL语句时或者涉及到对多个表的操作时就要考虑用存储过程;当在一个事务的完成需要很复杂的商业逻辑时(比如,对多个数据的操作,对多个状态的判断更改等)要考虑;还有就是比较复杂的统计和汇总也要考虑,但是过多的使用存储过程会降低系统的移植性。

上一篇:重命名存储过程


下一篇:解决PHP PclZip 中文乱码问题