存储过程
常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(StoredProcedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。
一个存储过程是一个可编程的函数(存储过程无返回值),它在数据库中创建并保存。它由SQL语句和一些特殊的控制结构组成。
存储过程能实现较快的执行速度。
如果某一操作包含大量的Transaction-SQL代码或分别被多次执行,那么存储过程要比批处理的执行速度快很多。
因为存储过程是预编译的。在首次运行一个存储过程时查询,优化器对其进行分析优化,并且给出最终被存储在系统表中的执行计划。
而批处理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。
存储过程能过减少网络流量。
针对同一个数据库对象的操作(如查询、修改),如果这一操作所涉及的Transaction-SQL语句被组织程存储过程。
那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大增加了网络流量并降低了网络负载。
存储过程可被作为一种安全机制来充分利用。
系统管理员通过执行某一存储过程的权限进行限制,能够实现对相应的数据的访问权限的限制,避免了非授权用户对数据的访问,保证了数据的安全。
语法格式
MySQL存储过程创建的格式:CREATE PROCEDURE 过程名([过程参数[,…]])[特性 …]过程体;
IN-输入参数:表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值; OUT-输出参数:该值可在存储过程内部被改变,并可返回; INOUT-输入输出参数:调用时指定,并且可被改变和返回
CREATE PROCEDURE `pinout`(INOUT `pinout` int) BEGIN #Routine body goes here... IF pinout = 0 THEN SELECT COUNT(*) FROM c_user into pinout; ELSE set pinout = -1; END IF; END
(1)注意的是DELIMITER //和DELIMITER ;两句【一定注意delimiter与// 或者 ; 之间有空格!】,DELIMITER是分割符的意思,因为MySQL默认以”;”为分隔符,如果没有声明分割符,那么编译器会把存储过程当成SQL语句进行处理,则存储过程的编译过程会报错。
所以要事先用DELIMITER关键字申明当前段分隔符,这样MySQL才会将”;”当做存储过程中的代码,不会执行这些代码,用完了之后要把分隔符还原。delimiter ;
(2)存储过程根据需要可能会有输入、输出、输入输出参数,这里有一个输出参数s,类型是int型,如果有多个参数用”,”分割开。
(3)过程体的开始与结束使用BEGIN与END进行标识。
变量定义
- 需在过程体前声明局部变量;
- 作用范围在begin end 之间;
DECLARE variable_name [,variable_name...] datatype [DEFAULT value];
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...]
//存储过程中 begin ...// set number = 10; -- 为变量赋值 select number; -- 获取变量值 end
用户变量
①用户变量名一般以@开头 ;
②用户变量作用域范围为当前客户端;
可在存储过程外部查看该用户变量。
//navicat for mysql 工具中 set @number =10; -- 为变量赋值 select @number; -- 获取变量值 -- 或者 select 'hello' into @A; select @A;
存储过程查看
查看数据库中创建的存储过程,有如下几种方式:
① show procedure status where db='数据库名'; ② select routine_name from information_schema.routines where routine_schema='数据库名'; ③ select name from mysql.proc where db=’数据库名’;
【查看存储过程创建语句】
可以像查看表创建语句一样查看存储过程创建详细:
SHOW CREATE PROCEDURE [数据库.]存储过程名;
-- 当前数据库下查询不需要数据库名
修改存储过程
使用ALTER语句可以修改存储过程或函数的特性,只能修改特性,如果想修改过程体只能删除存储过程再重新创建。
MySQL中修改存储过程和函数的语句的语法形式如下:
ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]
characteristic:
{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
其中释义如下:
① sp_name参数表示存储过程或函数的名称;
② characteristic参数指定存储函数的特性。
③ CONTAINS SQL表示子程序包含SQL语句,但不包含读或写数据的语句;
④ NO SQL表示子程序中不包含SQL语句;
⑤ READS SQL DATA表示子程序中包含读数据的语句;
⑥ MODIFIES SQL DATA表示子程序中包含写数据的语句。
⑦ SQL SECURITY { DEFINER | INVOKER }指明谁有权限来执行。
⑧ DEFINER表示只有定义者自己才能够执行;
⑨ INVOKER表示调用者可以执行;
⑩ COMMENT ‘string’是注释信息。
说明:修改存储过程使用ALTER PROCEDURE语句,修改存储函数使用ALTER FUNCTION语句。
ALTER PROCEDURE proc1
SQL SECURITY INVOKER;
-- 指明调用者可以执行
查询结果状态:
SELECT SPECIFIC_NAME,SQL_DATA_ACCESS,
SECURITY_TYPE FROM
information_schema.Routines WHERE ROUTINE_NAME='proc1' ;
删除存储过程
DROP PROCEDURE procName ;-- 删除存储过程
存储过程中的控制语句
if …then …elseif ….then…else..end if
begin if pincut=0 then select * from t_user; elseif pincut=1 then set pincut=1; else set pincut=2; end if; end
case ..when ..then..else..end case
BEGIN DECLARE s int ; set s = param+1; CASE s mod 2 WHEN 0 THEN select CONCAT(param,' is 奇数'); ELSE select CONCAT(param,' is 偶数'); end CASE; END
while ··do·· end while
BEGIN declare var int; -- WHILE ...DO...END WHILE... set var=0; while var<6 do insert into t_user(age) value(var); set var=var+1; end while; END
repeat··until·· end repeat
begin -- repeat ...end repeat declare v int; set v=0; repeat insert into t_user(age) values(v); set v=v+1; until v>=5 -- 循环控制语句 end repeat; -- 结束循环 end
loop ·····end loop
loop循环不需要初始条件,这点和while循环相似,同时和repeat循环一样不需要结束条件, leave语句的意义是离开循环
begin -- LOOP_LABLE:loop ....leave LOOP_LABLE.....end loop; declare v int; set v=7; LOOP_LABLE:loop //LABLES标号 insert into t_user(age) values(v); set v=v+1; if v >=20 then leave LOOP_LABLE; //跳出循环 end if; end loop; end
需要说明的是LABLES标号:
标号可以用在begin,repeat,while或者loop语句前,语句标号只能在合法的语句前面使用。
可以跳出循环,使运行指令达到复合语句的最后一步。
标号用在begin前示例如下:
create procedure proc11(in v_num int,out o_result int) zero_back:begin IF v_num <> 4 THEN set o_result = -1; LEAVE zero_back; -- 跳出函数,不再向下执行 END IF; insert into t_user(age) values(v_num); select count(*) into o_result from t_user; end
leave 相当于break,跳出循环。根据标号位置不同,甚至可以跳出函数
① 创建存储过程声明局部变量时不加 @(如DECLARE id int unsigned DEFAULT 20 (非用户变量));
② 但是无论从Mysql客户端下或者Navicat for MySQL ,使用用户变量参数(用户变量)要加 @ 符号如call proc1(@x);。
③ 调用存储过程使用call procedure(param);
call proc1('tom');-- 只有一个in型参数,传值进入 call proc2('tom',@result);--result为out(inout)型参数 select @result;-- 查看返回结果 如果@result提前赋值,将会被清空后再传入存储过程内部。
in 型参数
- in型参数不会改变传入的变量值 ;
CREATE DEFINER=`root`@`localhost` PROCEDURE `IDENTITY`(in id INT) BEGIN select id; -- 这里将传进来的参数先进行了查询,前提是参数必须已经赋值(默认为null) SELECT COUNT(*)+1 FROM c_user INTO id ; select id; END
- test code :
set @id = 0; -- -- 参数已经赋值(默认为null) CALL IDENTITY(@id); select @id;
- result as follows :

如果在存储过程内部改变了@id值,如下:
set @id :=100;
那么,无论在存储过程内部还是外部查看该变量值,都将改变:
select @id;
-- 结果100。
out 型参数
只允许过程内部使用(不用外部数据),给外部使用(引用传递:外部的数据会先被清空才会进入内部);
只能是变量(navicat或dos下调用存储过程,如果mybatis中调用存储过程,赋值不起作用)。
out型参数会在存储过程结束后,将对应的局部变量值重新返回给传入的用户变量。
CREATE DEFINER=`root`@`localhost` PROCEDURE `proc1`(OUT s int) BEGIN select s;-- 会先清空传入的变量值,此时显示为null SELECT COUNT(*) INTO s FROM c_user; set s = s+1; select s;-- 将此值重新赋值给@id; END
test code:
set @id = 0; CALL proc1(@id); select @id;

参考:
https://blog.csdn.net/J080624/article/details/72331013
浙公网安备 33010602011771号