zoukankan      html  css  js  c++  java
  • MySQL 游标

    MySQL 游标

     

    • SQL语句是“面向集合编程”,重点在于“获得什么”,而不是“如何获得”。
    • 有时候我们不需要对查询结构集的每一条都进行相同的操作,而是只操作其中的某些行,这时候就需要面向过程的编程方法,而游标就是面向过程编程方式的体现
    • 游标就相当于“指针”,它一次只指向一行
    • 游标的作用就是用于对查询数据库所返回的记录进行遍历,以便进行相应的操作

    游标的使用

    声明(给定结果集)、打开、通过游标获取数据、关闭、释放游标

    • 声明,给定结果集,存储过程结束后游标就被清理

      DECLARE cursor_name CURSOR FOR (SELECT...);
      
    • 打开游标,将结果集送到游标工作区

      OPEN cursor_name;
      
    • 通过游标获取数据

      游标先判断当前行是否为空,若为空则改变done,若不为空则将数据存放到临时变量中,读取后进入下一行为下次读取做准备。

      一定要想明白FETCH的运行方式,不然可能会出现重复FETCH到数据的情况

      FETCH cursor_name INTO (变量名s);
      
    • 关闭游标

      CLOSE cursor_name;
      
    • 因为每次调用FETCH游标就会尝试下一行,因此还要声明一个 NOT FOUND处理程序来处理游标读取不到下一行的情况

      DECLARE CONTINUE HANDLER FOR not found SET done = true;
      

      或者

      DECLARE CONTINUE HANDLER FOR SQLSTATE ‘02000’ SET done = true;
      

      SQLSTATE '02000'可以看做和not found一样,SQLSTATE '02000'是当没有更多的行以供循环时出现的一个条件。

      上面两种都可行,至于done赋值为true还是为1,就要看done是如何定义的,当然定义为INIT的为可以初始化为true

       

    使用举例1

    现有如下数据表

    mysql> select * from t;
    +----+------+-----------------+
    | id | nums | content         |
    +----+------+-----------------+
    |  1 |    2 | NULL            |
    |  2 |    6 | 二六一十二      |
    |  3 |    3 | 三三得九        |
    +----+------+-----------------+
    3 rows in set (0.00 sec)
    

    我们通过游标读取每一行并实现将nums导入到新数据表中,在实际工作中这种方式可以大大减少我们"分表"时的操作难度。

    DELIMITER //
    
    CREATE PROCEDURE transferData()
    BEGIN
    DECLARE temp_num INT;
    DECLARE done BOOLEAN DEFAULT false;
    DECLARE cur CURSOR FOR select nums FROM t;
    DECLARE continue HANDLER FOR not found SET done = true;
    
    CREATE TABLE IF NOT EXISTS t2 (auto_id int PRIMARY KEY AUTO_INCREMENT, val int not null);
    
    OPEN cur;
    REPEAT
    IF NOT done THEN
    FETCH cur INTO temp_num;
    INSERT INTO t2 (val) VALUES (temp_num);
    END IF;
    UNTIL done=true END REPEAT;
    CLOSE cur;
    SELECT * from t2;
    END//
    
    DELIMITER ;
    

    执行该存储过程后自动显示如下结果:

    mysql> select * from t2;
        -> //
    +---------+-----+
    | auto_id | val |
    +---------+-----+
    |       1 |   2 |
    |       2 |   6 |
    |       3 |   3 |
    |       4 |   3 |
    +---------+-----+
    4 rows in set (0.00 sec)
    

    我们会发现,为什么这里多了一行数据?看起来是被重复FETCH并插入了,究其原因,是因为没有理清楚FETCH的运作方式---没有搞清楚什么时候FETCH会改变done

    如果我们改成

    CREATE PROCEDURE transferData2()
    BEGIN
    DECLARE temp_num INT;
    DECLARE done BOOLEAN DEFAULT false;
    DECLARE cur CURSOR FOR select nums FROM t;
    DECLARE continue HANDLER FOR not found SET done = true;
    
    CREATE TABLE IF NOT EXISTS t3 (auto_id int PRIMARY KEY AUTO_INCREMENT, val int not null);
    
    OPEN cur;
    REPEAT
    FETCH cur INTO temp_num;
    IF NOT done THEN
    INSERT INTO t3 (val) VALUES (temp_num);
    END IF;
    UNTIL done=true END REPEAT;
    CLOSE cur;
    SELECT * from t3;
    END//
    

    则结果会符合我们的预期

    mysql> select * from t3//
    +---------+-----+
    | auto_id | val |
    +---------+-----+
    |       1 |   2 |
    |       2 |   6 |
    |       3 |   3 |
    +---------+-----+
    3 rows in set (0.00 sec)
    

     

  • 相关阅读:
    3.node.js AssertionError: false == true错误解决
    9.获取当前时区时间和utc时间的工具方法
    2.Express封装mysq方法
    1.Express初识
    poj 3617
    前缀和
    pop 反序列化
    Reverse前两个题
    前两个Web题
    Misc
  • 原文地址:https://www.cnblogs.com/G-Aurora/p/13219895.html
Copyright © 2011-2022 走看看