Q:为什么要使用游标?
A:
在存储过程 (或函数) 中,如果某条 select 语句返回的结果集中只有 1 行,可以使用 select into 语句 (上几篇博客有介绍到用法) 来得到该行进行处理;如果结果集中有多行,简单的 select 语句成批地进行处理,需要在检索出来的行中前进或后退一行或多行…… 若是想得到其中的每一行进行处理,就必须使用游标。
Q:什么是游标?
A:
游标 (cursor),是一个存储在 MySQL 服务器上的数据库查询,游标不是一条 SELECT 语句,而是被该语句检索出来的结果集;可以看做是指向查询结果集的指针;通过 cursor,就可以一次一行的从结果集中把行拿出来处理。
注意:MySQL 游标只能用于存储过程和函数。
游标的处理过程:4 步
①声明游标 declare:没有检索数据,只是定义要使用的 select 语句
②打开游标 open:打开游标以供使用,用上一步定义的 select 语句把数据实际检索出来
③检索游标 fetch:对于填有数据的游标,根据需要取出 (检索) 各行
④关闭游标 close:在结束游标使用时,必须关闭游标
1、声明游标
DECLARE cursor_name CURSOR FOR select_statement;
声明一个游标 cursor_name,让其指向查询 select_statement 的结果集。
注意:
①游标声明必须出现在变量和条件声明的后面,但是在异常处理声明的前面
②一个过程中可以有多个游标声明
2、打开游标
OPEN cursor_name;
cursor_name 是声明中定义的名字;打开游标时才执行相应的 select_statement。
3、检索游标
FETCH cursor_name INTO var_name [, var_name] ...
从游标 cursor_name 中拿出一行,把该行的各个列值保存到各个变量中。
解析:
一次只拿一行,拿完后,自动移动指针到下一行;
如果没有拿到行,会抛出异常,其 SQLSTATE 代码值为'02000',此时要检测到该情况,需要声明异常处理程序 (针对条件 NOT FOUND 也可以),通常需要在一个循环中来执行 fetch 语句,通过检测以上异常来结束循环。
4、关闭游标
CLOSE cursor_name;
收回游标占用的内存,别浪费资源嘛。
例 1:创建过程,计算 players 表中行的数量
- mysql> delimiter $$
- mysql> create procedure number_of_players(
- ->outpnumberint)
- -> begin
- -> declare a_playernoint;
- -> declare foundbool default true;循环控制变量,其值为false时循环结束
- ->
- -> declare c_players cursorfor->selectplayernofromPLAYERS;①声明游标
- ->
- -> declarecontinuehandlerfor not found
- ->setfound=false;声明异常处理程序
- ->
- ->setpnumber=0;
- ->
- ->open c_players;②打开游标
- ->
- ->fetch c_players into a_playerno;③检索游标(检索第一行)
- ->whilefounddo->setpnumber=pnumber+1;
- -> fetch c_players into a_playerno;
- -> endwhile;循环检索其余行
- ->
- ->close c_players;④关闭游标
- -> end$$
- mysql> delimiter ;
- mysql> call number_of_players(@pnumber);
- mysql>select @pnumber;
- +----------+
- | @pnumber |
- +----------+
- |14|
- +----------+
- mysql>selectcount(*)from PLAYERS;
- +----------+
- | count(*) |
- +----------+
- |14|
- +----------+
例 2:创建过程,计算某个球员的罚款次数 -- 游标声明中可以包含变量
- mysql> delimiter $$
- mysql> create procedure number_penalties(
- ->inp_playernoint,
- ->outpnumberint)
- -> begin
- -> declare a_playernoint;
- -> declare foundbool default true;循环控制变量
- ->
- -> declare c_players cursorfor 声明游标
- ->select playerno
- ->from PENALTIES
- ->whereplayerno =p_playerno;包含变量p_playerno
- ->
- -> declarecontinuehandlerfor not found
- ->setfound=false;声明异常处理程序
- ->
- ->setpnumber=0;
- ->
- ->open c_players;打开游标
- ->
- -> fetch c_players into a_playerno;
- ->whilefounddo 循环检索游标每一行
- ->setpnumber=pnumber+1;
- -> fetch c_players into a_playerno;
- -> endwhile;
- ->
- ->close c_players;关闭游标
- -> end$$
- mysql> delimiter ;
- mysql> call number_penalties(44,@pnumber);
- mysql>select @pnumber;
- +----------+
- | @pnumber |
- +----------+
- |3|
- +----------+
来源: http://www.cnblogs.com/geaozhang/p/6817637.html