mysql游标的用法及作用
本文内容纲要:
-【简介】
-【用法】
-【实例】
-游标嵌套
-动态SQL
例子:
当前有三张表A、B、C其中A和B是一对多关系,B和C是一对多关系,现在需要将B中A表的主键存到C中;
常规思路就是将B中查询出来然后通过一个update语句来更新C表就可以了,但是B表中有2000多条数据,
难道要执行2000多次?显然是不现实的;最终找到写一个存储过程然后通过循环来更新C表,
然而存储过程中的写法用的就是游标的形式。
【简介】
游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。
游标充当指针的作用。
尽管游标能遍历结果中的所有行,但他一次只指向一行。
游标的作用就是用于对查询数据库所返回的记录进行遍历,以便进行相应的操作。
【用法】
一、声明一个游标:declare游标名称CURSORfortable;(这里的table可以是你查询出来的任意集合)
二、打开定义的游标:open游标名称;
三、获得下一行数据:FETCH游标名称intotestrangeid,versionid;
四、需要执行的语句(增删改查):这里视具体情况而定
五、释放游标:CLOSE游标名称;
注:mysql存储过程每一句后面必须用;结尾,使用的临时字段需要在定义游标之前进行声明。
【实例】
-
BEGIN
--定义变量
declaretestrangeidBIGINT;
declareversionidBIGINT;
declaredoneint;
--创建游标,并存储数据
declarecur_testCURSORfor
selectidastestrangeid,version_idasversionidfromtp_testrange;
--游标中的内容执行完后将done设置为1
DECLARECONTINUEHANDLERFORNOTFOUNDSETdone=1;
--打开游标
opencur_test;
--执行循环
posLoop:LOOP
--判断是否结束循环
IFdone=1THEN
LEAVEposLoop;
ENDIF;
--取游标中的值
FETCHcur_testintotestrangeid,versionid;
--执行更新操作
updatetp_data_executesetversion_id=versionidwheretestrange_id=testrangeid;
ENDLOOPposLoop;
--释放游标
CLOSEcur_test;
END
-
例子2:
我们现在要用存储过程做一个功能,统计iphone的总库存是多少,并把总数输出到控制台。
--在windows系统中写存储过程时,如果需要使用declare声明变量,需要添加这个关键字,否则会报错。
delimiter//
dropprocedureifexistsStatisticStore;
CREATEPROCEDUREStatisticStore()
BEGIN
--创建接收游标数据的变量
declarecint;
declarenvarchar(20);
--创建总数变量
declaretotalintdefault0;
--创建结束标志变量
declaredoneintdefaultfalse;
--创建游标
declarecurcursorforselectname,countfromstorewherename='iphone';
--指定游标循环结束时的返回值
declarecontinueHANDLERfornotfoundsetdone=true;
--设置初始值
settotal=0;
--打开游标
opencur;
--开始循环游标里的数据
read_loop:loop
--根据游标当前指向的一条数据
fetchcurinton,c;
--判断游标的循环是否结束
ifdonethen
leaveread_loop;--跳出游标循环
endif;
--获取一条数据时,将count值进行累加操作,这里可以做任意你想做的操作,
settotal=total+c;
--结束游标循环
endloop;
--关闭游标
closecur;
--输出结果
selecttotal;
END;
--调用存储过程
callStatisticStore();
fetch是获取游标当前指向的数据行,并将指针指向下一行,当游标已经指向最后一行时继续执行会造成游标溢出。
使用loop循环游标时,他本身是不会监控是否到最后一条数据了,像下面代码这种写法,就会造成死循环;
read_loop:loop
fetchcurinton,c;
settotal=total+c;
endloop;
在MySql中,造成游标溢出时会引发mysql预定义的NOTFOUND错误,所以在上面使用下面的代码指定了当引发notfound错误时定义一个continue的事件,指定这个事件发生时修改done变量的值。
declarecontinueHANDLERfornotfoundsetdone=true;
所以在循环时加上了下面这句代码:
--判断游标的循环是否结束
ifdonethen
leaveread_loop;--跳出游标循环
endif;
如果done的值是true,就结束循环。继续执行下面的代码
使用方式
游标有三种使用方式:
第一种就是上面的实现,使用loop循环;
第二种方式如下,使用while循环:
dropprocedureifexistsStatisticStore1;
CREATEPROCEDUREStatisticStore1()
BEGIN
declarecint;
declarenvarchar(20);
declaretotalintdefault0;
declaredoneintdefaultfalse;
declarecurcursorforselectname,countfromstorewherename='iphone';
declarecontinueHANDLERfornotfoundsetdone=true;
settotal=0;
opencur;
fetchcurinton,c;
while(notdone)do
settotal=total+c;
fetchcurinton,c;
endwhile;
closecur;
selecttotal;
END;
callStatisticStore1();
第三种方式是使用repeat执行:
dropprocedureifexistsStatisticStore2;
CREATEPROCEDUREStatisticStore2()
BEGIN
declarecint;
declarenvarchar(20);
declaretotalintdefault0;
declaredoneintdefaultfalse;
declarecurcursorforselectname,countfromstorewherename='iphone';
declarecontinueHANDLERfornotfoundsetdone=true;
settotal=0;
opencur;
repeat
fetchcurinton,c;
ifnotdonethen
settotal=total+c;
endif;
untildoneendrepeat;
closecur;
selecttotal;
END;
callStatisticStore2();
游标嵌套
在mysql中,每个beginend块都是一个独立的scope区域,由于MySql中同一个error的事件只能定义一次,如果多定义的话在编译时会提示Duplicatehandlerdeclaredinthesameblock。
dropprocedureifexistsStatisticStore3;
CREATEPROCEDUREStatisticStore3()
BEGIN
declare_nvarchar(20);
declaredoneintdefaultfalse;
declarecurcursorforselectnamefromstoregroupbyname;
declarecontinueHANDLERfornotfoundsetdone=true;
opencur;
read_loop:loop
fetchcurinto_n;
ifdonethen
leaveread_loop;
endif;
begin
declarecint;
declarenvarchar(20);
declaretotalintdefault0;
declaredoneintdefaultfalse;
declarecurcursorforselectname,countfromstorewherename='iphone';
declarecontinueHANDLERfornotfoundsetdone=true;
settotal=0;
opencur;
iphone_loop:loop
fetchcurinton,c;
ifdonethen
leaveiphone_loop;
endif;
settotal=total+c;
endloop;
closecur;
select_n,n,total;
end;
begin
declarecint;
declarenvarchar(20);
declaretotalintdefault0;
declaredoneintdefaultfalse;
declarecurcursorforselectname,countfromstorewherename='android';
declarecontinueHANDLERfornotfoundsetdone=true;
settotal=0;
opencur;
android_loop:loop
fetchcurinton,c;
ifdonethen
leaveandroid_loop;
endif;
settotal=total+c;
endloop;
closecur;
select_n,n,total;
end;
begin
end;
endloop;
closecur;
END;
callStatisticStore3();
上面就是实现一个嵌套循环,当然这个例子比较牵强。凑合看看就行。
动态SQL
Mysql支持动态SQL的功能
set@sqlStr='select*fromtablewherecondition1=?';
prepares1for@sqlStr;
--如果有多个参数用逗号分隔
executes1using@condition1;
--手工释放,或者是connection关闭时,server自动回收
deallocateprepares1;
本文内容总结:【简介】,【用法】,【实例】,游标嵌套,动态SQL,
原文链接:https://www.cnblogs.com/loong-hon/p/11003189.html