转自:http://111cn.cn/database/110/a413d2d888f7a23e9d9ef3b4866cea3d.htm
-
MySQL存储过程例子,包含事务,参数,嵌套调用,游标,循环等
drop procedure if exists pro_rep_shadow_rs;
delimiter |
----------------------------------
-- rep_shadow_rs
-- 用来处理信息的增加,更新和删除
-- 每次只更新上次以来没有做过的数据
-- 根据不同的标志位
-- 需要一个输出的参数,
-- 如果返回为0,则调用失败,事务回滚
-- 如果返回为1,调用成功,事务提交
--
-- 测试方法
-- call pro_rep_shadow_rs(@rtn);
-- select @rtn;
----------------------------------
create procedure pro_rep_shadow_rs(out rtn int)
begin
-- 声明变量,所有的声明必须在非声明的语句前面
declare iLast_rep_sync_id int default -1;
declare iMax_rep_sync_id int default -1;
-- 如果出现异常,或自动处理并rollback,但不再通知调用方了
-- 如果希望应用获得异常,需要将下面这一句,以及启动事务和提交事务的语句全部去掉
declare exit handler for sqlexception rollback;
-- 查找上一次的
select eid into iLast_rep_sync_id from rep_de_proc_log where tbl='rep_shadow_rs';
-- 如果不存在,则增加一行
if iLast_rep_sync_id=-1 then
insert into rep_de_proc_log(rid,eid,tbl) values(0,0,'rep_shadow_rs');
set iLast_rep_sync_id = 0;
end if;
-- 下一个数字
set iLast_rep_sync_id=iLast_rep_sync_id+1;
-- 设置默认的返回值为0:失败
set rtn=0;
-- 启动事务
start transaction;
-- 查找最大编号
select max(rep_sync_id) into iMax_rep_sync_id from rep_shadow_rs;
-- 有新数据
if iMax_rep_sync_id>=iLast_rep_sync_id then
-- 调用
call pro_rep_shadow_rs_do(iLast_rep_sync_id,iMax_rep_sync_id);
-- 更新日志
update rep_de_proc_log set rid=iLast_rep_sync_id,eid=iMax_rep_sync_id where tbl='rep_shadow_rs';
end if;
-- 运行没有异常,提交事务
commit;
-- 设置返回值为1
set rtn=1;
end;
|
delimiter ;
drop procedure if exists pro_rep_shadow_rs_do;
delimiter |
---------------------------------
-- 处理指定编号范围内的数据
-- 需要输入2个参数
-- last_rep_sync_id 是编号的最小值
-- max_rep_sync_id 是编号的最大值
-- 无返回值
---------------------------------
create procedure pro_rep_shadow_rs_do(last_rep_sync_id int, max_rep_sync_id int)
begin
declare iRep_operationtype varchar(1);
declare iRep_status varchar(1);
declare iRep_Sync_id int;
declare iId int;
-- 这个用于处理游标到达最后一行的情况
declare stop int default 0;
-- 声明游标
declare cur cursor for select id,Rep_operationtype,iRep_status,rep_sync_id from rep_shadow_rs where rep_sync_id between last_rep_sync_id and max_rep_sync_id;
-- 声明游标的异常处理,设置一个终止标记
declare CONTINUE HANDLER FOR SQLSTATE '02000' SET stop=1;
-- 打开游标
open cur;
-- 读取一行数据到变量
fetch cur into iId,iRep_operationtype,iRep_status,iRep_Sync_id;
-- 这个就是判断是否游标已经到达了最后
while stop <> 1 do
-- 各种判断
if iRep_operationtype='I' then
insert into rs0811 (id,fnbm) select id,fnbm from rep_shadow_rs where rep_sync_id=iRep_sync_id;
elseif iRep_operationtype='U' then
begin
if iRep_status='A' then
insert into rs0811 (id,fnbm) select id,fnbm from rep_shadow_rs where rep_sync_id=iRep_sync_id;
elseif iRep_status='B' then
delete from rs0811 where id=iId;
end if;
end;
elseif iRep_operationtype='D' then
delete from rs0811 where id=iId;
end if;
-- 读取下一行的数据
fetch cur into iId,iRep_operationtype,iRep_status,iRep_Sync_id;
end while; -- 循环结束
close cur; -- 关闭游标
end;use testprocedure;
delimiter //
create procedure simpleproce1 (out par1 int)
begin
select count(*) into par1 from proce;
end
//delimiter ;
call simpleproce1(@a);select @a;
#<2>,每次只有单一的行可以被取回select id,name into par1,par2 from proce LIMIT 1;中的LIMIT 1;
use testprocedure;
delimiter //
DROP procedure IF EXISTS simpleproce2
create procedure simpleproce2 (out par1 int,out par2 char(30))
begin
select id,name into par1,par2 from proce LIMIT 1;
end
//delimiter ;
call simpleproce2(@a,@b);select @a,@b;
## *********second test,function************
#<3>
delimiter //DROP FUNCTION IF EXISTS hello
//create function hello(s char(20)) returns char(50)
return concat('Hello, ',s,'!');
//delimiter ;
select hello('world');show create function testprocedure.helloG
#它返回子程序的特征,如数据库 ,名字,类型,创建者及创建和修改日期
show function status like 'hello'G#<4>
#注意name不能和字段名相同
delimiter //
DROP procedure IF EXISTS test //CREATE PROCEDURE test ()
BEGIN
DECLARE name VARCHAR(5) DEFAULT 'bob';
DECLARE newname VARCHAR(5);
DECLARE xid INT;
SELECT name,id INTO newname,xid
FROM proce WHERE name = name;
SELECT newname;
END;
//call test1() //
#***
delimiter //
DROP procedure IF EXISTS test2 //CREATE PROCEDURE test2 ()
BEGIN
DECLARE newname VARCHAR(5);
DECLARE xid INT;
SELECT name,id INTO newname,xid
FROM proce limit 1;
SELECT newname,xid;
END;
//call test2() //
#<5>
use testprocedure;
CREATE PROCEDURE p1 () SELECT * FROM proce;call p1();
#<6>注意此处的handler是设置SQLSTATE值,SQLWARNING是对所有以01开头的SQLSTATE代码的速记
#NOT FOUND是对所有以02开头的SQLSTATE代码的速记
#SQLEXCEPTION是对所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE代码的速记
#DECLARE CONTINUE HANDLER声明CONTINUE异常处理
#事实上这里的23000SQLSTATE是更常用的,当外键约束出错或主键约束出错就被调用了。
#当没有发生该23000异常时, select @x2的值将是null,而不是1,
#并且后面的第2个语句执行时将会报主键约束错误,此时@x2=1,@x=4,虽然第2句有了异常,但是后面的语句继续执行
#保存到数据的数据是3,test3和5,test5use testprocedure;
delimiter //
DROP procedure IF EXISTS handlerdemo
//create procedure handlerdemo()
begin
declare continue handler for sqlstate '23000' set @x2=1;
set @x=1;
insert into proce values(3,'test3');
set @x=2;
insert into proce values(3,'test4');
set @x=3;
insert into proce values(5,'test5');
set @x=4;
end;
//call handlerdemo()//
select @x //
select @x2 //## ************光标****************
#<7>光标必须在声明处理程序之前被声明,并且变量和条件必须在声明光标或处理程序之前被声明
#在这里先声明变量a,b,c,后声明cursor
create procedure curdemo()
begin
declare done int default 0;
declare a char(16);
declare b,c int;
declare cur1 cursor for select id,name from proce;
declare cur2 cursor for select id from proce2;
declare continue handler for sqlstate '02000' set done=1;
open cur1;
open cur2;repeat
fetch cur1 into b,a;
fetch cur2 into c;
if not done then
if b<c then
insert into proce3 values(b,a);
else
insert into proce3 values(c,a);
end if;
end if;
until done end repeat;
close cur1;
close cur2;
end## **************** Case *******************
#<8>when ... then ;case ... end case;
delimiter //
DROP procedure IF EXISTS p13
//
create procedure p13(in par1 int)
begin
declare var1 int;
set var1=par1+1;
case var1
when 0 then insert into casetest values(17);
when 1 then insert into casetest values(18);
else insert into casetest values(19);
end case;
end;
//call p13(-1)//
call p13(0)//
call p13(1)//
call p13(null)//
## **************** while ****************
#<9>while ... do ... end while;为了防止null的错误,set v=0是必须的
delimiter //
DROP procedure IF EXISTS p14
//create procedure p14()
begin
declare v int;
set v=0;
while v < 5 do
insert into casetest values (v);
set v=v+1;
end while;
end;//call p14()//
## ***************** repeat *****************
#<10>repeat ...until ... end repeat; 是执行后检查(until v>=5),而while是执行前检查(while v<5)
delimiter //
DROP procedure IF EXISTS p15
//create procedure p15()
begin
declare v int;
set v=0;
repeat
insert into casetest values(v);
set v=v+1;
until v >=5end repeat;
end;
//call p15()//
## ***************** loops *****************
#<11> loop 和while一样不需要初始条件,同时和repeat一样不需要结束条件
# loop_label: loop
# ...
# if .. then
# leave loop_label
# end if
# end loopdelimiter //
DROP procedure IF EXISTS p16
//create procedure p16()
begin
declare v int;
set v=0;
loop_label: loop
insert into casetest values(v);
set v=v+1;
if v >=5 then
leave loop_label;
end if;
end loop;
end;//call p16()//
## ***************** Labels *****************
# <12>labels标号; 注意此处的until 0=0后面没有分号“;”
delimiter //
DROP procedure IF EXISTS p17//create procedure p17()
label_1:beginlabel_2:while 0=1 do leave label_2; end while;
label_3:repeat leave label_3;until 0=0 end repeat;
label_4:loop leave label_4; end loop;
end;//
call p17()//
#<13>labels 标号结束符;
delimiter //
DROP procedure IF EXISTS p18//create procedure p18()
label_1:beginlabel_2:while 0=1 do leave label_2; end while label_2;
label_3:repeat leave label_3;until 0=0 end repeat label_3;
label_4:loop leave label_4; end loop label_4;
end label_1;//
call p18()//
#<14>leave和labels 跳出和标号;leave 使程序跳出复杂的语句
delimiter //
DROP procedure IF EXISTS p19//create procedure p19(par char)
label_1:begin
label_2:begin
label_3:beginif par is not null then
if par='a' then leave label_1;
else
begin
if par='b' then
leave label_2;
else
leave label_3;
end if;
end;
end if;
end if;end label_3;
end label_2;
end label_1;//
call p19('a')//
#<15>iterate迭代,必须用leave;iterate意思是重新开始复合语句,相当于 continue
#该结果中3将不被保存到数据库表中
delimiter //
DROP procedure IF EXISTS p20//create procedure p20()
begin
declare v int;
set v=0;
loop_label:loopif v=3 then
set v=v+1;
iterate loop_label;
end if;
insert into casetest values(v);
set v=v+1;if v>=5 then
leave loop_label;
end if;end loop loop_label;
end;//call p20()//
#<16>Grand combination大组合delimiter //
DROP procedure IF EXISTS p21//create procedure p21(in par1 int,out par2 int)
language sql deterministic sql security invoker
begin
declare v int;label goto_label;
start_label:loop
if v=v then
leave start_label;
else
iterate start_label;
end if;
end loop start_label;
repeat
while 1=0 do begin end;
end while;
until v=v
end repeat;goto goto_label;
end;
//call p21()//
## **************** trigger ***************************
#<17>
use testprocedure;CREATE TABLE trig1(a1 int);
CREATE TABLE trig2(a2 int);
CREATE TABLE trig3(a3 int not null AUTO_INCREMENT PRIMARY KEY);CREATE TABLE trig4(
a4 INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
b4 INT DEFAULT 0
);insert into trig3(a3) values(null),(null),(null),(null),(null),(null),(null),(null),(null),(null);
insert into trig4(a4) values(0),(0),(0),(0),(0),(0),(0),(0),(0),(0);delimiter //
DROP trigger trigtest//create trigger trigtest before insert on trig1
for each row begin
insert into trig2 set a2=NEW.a1;
delete from trig3 where a3=NEW.a1;
update trig4 set b4=b4+1 where a4=NEW.a1;
end;
//
delimiter ;INSERT INTO trig1 VALUES(1), (3), (1), (7), (1), (8), (4), (4);