简单介绍游标
在检索出来的行中,前进或者后退一行或多行,就需要用到所谓的“游标”。
游标不是某个SELECT语句,但是它是被该语句检索出来的结果集。
几个特点:
·MySQL游标只能用于存储过程(和函数)。
·游标是不能滚动的,也就是只能在一个方向上进行遍历,不能在记录之间随意进退,不能跳过某些记录。
使用步骤
1. 用DECLARE语句声明一个游标。
在能够使用游标前,必须声明(定义)它。定义要使用的select语句。
DECLARE cursor_name CURSOR FOR SELECT_statement;
2. 使用OPEN语句来打开上面你定义的游标。
一旦声明后,必须打开游标以提供使用。这个过程用前面定义的select语句把数据实际检索出来。
OPEN cursor_name;
3. 用FETCH语句来获得下一行数据。
FETCH是从第一行开始,获取当前行的数据,每次执行后会移动内部行指针,再次调用FETCH则会检索到下一行(不会重复读取同一行)。
FETCH cursor_name INTO variable list;
注意,尤其在循环中不要忘记用Fetch取下一行。
4. 在结束游标使用时,必须关闭游标。
在OPEN时才执行查询,存储检索出的数据以供浏览和滚动。在游标使用完成后,使用CLOSE进行关闭。
CLOSE cursor_name;
在WHILE循环中的使用游标
WHILE语法构造:
while 布尔表达式 do
语句序列;
end while
下面是游标与WHILE循环一起使用的例子。
示例中的 表cur_test1, 表cur_test2结构相同,如下。
(用了与mysql自带的 sakila.country 相同的结构,且往cur_test1 insert了sakila.country的数据:
INSERT INTO cur_test1 SELECT * FROM sakila.country; )
Create Table: CREATE TABLE `cur_test1` (
`country_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`country` varchar(50) NOT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`country_id`)
) ENGINE=InnoDB AUTO_INCREMENT=110 DEFAULT CHARSET=utf8
这个例子是把 表cur_test1 中的相应数据copy到 表cur_test2中。
(注意这里仅关注游标cursor与循环的用法)
其他在以下存储过程的SQL的注释中进行了解释。
DELIMITER //
DROP PROCEDURE IF EXISTS cur_while_test;
CREATE PROCEDURE cur_while_test()
BEGIN
DECLARE done int;
DECLARE x_country_id smallint(5);
DECLARE x_country varchar(50);
DECLARE x_last_update timestamp;
/*First: Delcare a cursor,首先这里对游标进行定义*/
DECLARE cur1 CURSOR FOR
SELECT
country_id,
country,
last_update
FROM cur_test1
ORDER BY country_id;
/*when "not found" occur,just continue,这个是个条件处理,针对NOT FOUND的条件*/
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
/*本例适用,本例是insert语句,为可多次执行本存储过程准备的语句*/
TRUNCATE TABLE cur_test2;
SET done = 0;
/*Second: Open the cursor 接着使用OPEN打开游标*/
OPEN cur1;
/*Third: now you can Fetch the row 把第一行数据写入变量中,游标也随之指向了记录的第一行*/
FETCH cur1 INTO x_country_id,
x_country,
x_last_update;
WHILE done = 0 DO
INSERT INTO cur_test2(
country_id,
country,
last_update
)
VALUES(
x_country_id,
x_country,
x_last_update
);
/*抓下一行数据,否则 WHILE done=0 这个条件永远成立,变成无限插入第一行数据的死循环*/
FETCH cur1 INTO x_country_id,
x_country,
x_last_update;
END WHILE;
/*Finally: cursor need be closed 用完后记得用CLOSE把资源释放掉*/
CLOSE cur1;
END
在REPEAT循环中的使用游标
REPEAT语法构造:
repeat
语句序列;
util 布尔表达式
end repeat
下面是游标与REPEAT循环一起使用的例子。
与上面while循环的例子相同,这个例子是把 表cur_test1 中的相应数据copy到 表cur_test2中。
(注意这里仅关注游标cursor与循环的用法)
其他在以下存储过程的SQL的注释中进行了解释。
DELIMITER //
DROP PROCEDURE IF EXISTS cur_repeat_test;
CREATE PROCEDURE cur_repeat_test()
BEGIN
DECLARE done int;
DECLARE x_country_id smallint(5);
DECLARE x_country varchar(50);
DECLARE x_last_update timestamp;
/*First: Delcare a cursor,首先这里对游标进行定义*/
DECLARE cur1 CURSOR FOR
SELECT
country_id,
country,
last_update
FROM cur_test1
ORDER BY country_id;
/*when "not found" occur,just continue,这个是个条件处理,针对NOT FOUND的条件*/
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
/*本例适用,本例是insert语句,为可多次执行本存储过程准备的语句*/
TRUNCATE TABLE cur_test2;
SET done = 0;
/*Second: Open the cursor 接着使用OPEN打开游标*/
OPEN cur1;
/*Third: now you can Fetch the row 把第一行数据写入变量中,游标也随之指向了记录的第一行*/
FETCH cur1 INTO x_country_id,
x_country,
x_last_update;
REPEAT
INSERT INTO cur_test2(
country_id,
country,
last_update
)
VALUES(
x_country_id,
x_country,
x_last_update
);
/*不要忘了抓下一行数据*/
FETCH cur1 INTO x_country_id,
x_country,
x_last_update;
UNTIL done = 1
END REPEAT;
/*Finally: cursor need be closed 用完后记得用CLOSE把资源释放掉*/
CLOSE cur1;
END