我们如果要在MySQL的存储过程中遍历一个查询语句的结果集,需要使用到游标cursor(SQL server中可以定义表类型的变量Table,但MySQL中不行)。
    假设我需要从 tb_stu 这张表中查询出所有记录插入到tb_stu_copy1中,等价于insert into tb_stu_copy1 select * from tb_stu;
    1592213728(1).jpg
    以下是存储过程的具体sql

    1. CREATE PROCEDURE curdemo ()
    2. BEGIN
    3. DECLARE stop_flag INT DEFAULT 0;
    4. DECLARE this_id INT;
    5. DECLARE this_name VARCHAR ( 100 );
    6. DECLARE this_sex VARCHAR ( 2 );
    7. DECLARE cu CURSOR FOR SELECT * FROM tb_stu;
    8. DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET stop_flag = 1;#当fetch游标到了结果即最后一行的时候,设置stop_flag=1
    9. OPEN cu;#定义完游标之后要打开游标
    10. FETCH cu INTO this_id, this_name, this_sex;#读取数据到游标
    11. WHILE
    12. stop_flag <> 1 DO
    13. INSERT INTO tb_stu_copy1
    14. VALUES
    15. ( this_id, this_name, this_sex );
    16. FETCH cu INTO this_id, this_name, this_sex;
    17. END WHILE;
    18. CLOSE cu;#关闭游标
    19. END

    我们使用游标的公式步骤大概如下:

    1. 定义游标变量 DECLARE 游标变量名 CURSOR FOR 查询语句
    2. 定义一个当游标移动到末尾时执行的操作 DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' 具体操作代码
    3. 打开游标 OPEN 游标变量名
    4. 用 FETCH 关键字存查询结果集中获取数据
    5. 循环遍历(注意MySQL存储过程中不能用for循环)
    6. 关闭游标 CLOSE 游标变量名


    这里有一段代码值得注意

    1. DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET stop_flag = 1;

    这句话是声明了一个句柄,当 sqlstate 的值为’02000’ 时会执行这个句柄,从而使stop_flag设置为1。而 sqlstate '02000' 是什么意思呢?sqlstate正常状态是返回’00000’的,当发生下述异常之一时,sqlstate就会变成02000

    • SELECT INTO 语句或 INSERT 语句的子查询的结果为空表。
    • 在搜索的 UPDATE 或 DELETE 语句内标识的行数为零。
    • 在 FETCH 语句中引用的游标位置处于结果表最后一行之后。

    上述的第三种异常是符合我们的情况的。也就是说,将在遍历完所有结果集之后就会调用sqlstate变成02000。

    关于sqlstate更多的状态码,可以查看这篇博客:https://blog.csdn.net/cangyingaoyou/article/details/7402243

    这里边有一个关键字 continue ,这个关键字和 exit 关键字相对应的。 continue 语句执行完指定操作后继续循环,而 exit 语句会从最近的 begin...end 语句块中退出。这里指定的操作就是 SET stop_flag = 1 。我们给 stop_flag 设置为1之后continue就会继续循环,然后循环条件判断发现stop_flag <>1 不满足,于是while循环就结束了

    注意:句柄要定义在游标之后, 不然会报 1338 - Cursor declaration after handler declaration 错误。