MySQL Cursor 存储过程之游标与相关循环

简单介绍游标

在检索出来的行中,前进或者后退一行或多行,就需要用到所谓的“游标”。
游标不是某个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;  )

mysql> show create table cur_test1\G
*************************** 1. row ***************************
       Table: cur_test1
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
1 row in set (0.00 sec)

mysql> show create table cur_test2\G
*************************** 1. row ***************************
       Table: cur_test2
Create Table: CREATE TABLE `cur_test2` (
  `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=2 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

这个例子是把 表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
//

以上。

发布了26 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Olivia_Vang/article/details/100521749
今日推荐