MYSQL游标循环,多跑一圈,为啥?

Posted

技术标签:

【中文标题】MYSQL游标循环,多跑一圈,为啥?【英文标题】:MYSQL cursor loop, runs one extra round, why?MYSQL游标循环,多跑一圈,为什么? 【发布时间】:2012-08-30 18:30:30 【问题描述】:

我正在循环访问 mysql 存储过程中的游标结果集。我面临一个问题,即循环总是运行两次最后一条记录。这是我的代码,

BEGIN
DECLARE not_found_creadit INT DEFAULT 0;

DECLARE cur_credit CURSOR FOR 
SELECT customer_id, amount, status, user_type, employee, note FROM credit WHERE status = 'approved' AND customer_id = int_cust_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET not_found_creadit = 1;
OPEN cur_credit;
  SET not_found_creadit = 0;
  credit_loop : LOOP 
      IF not_found_creadit THEN
        CLOSE cur_credit;
        LEAVE credit_loop;
      END IF;
      FETCH cur_credit INTO vc_customer, dec_amount, vc_status, vc_user_type, vc_emp, vc_note;
      SELECT vc_customer, dec_amount, vc_status, vc_user_type, vc_emp, vc_note;
      ......
      ......
  END LOOP;
END;

表示如果我有 3 条记录,循环运行 4 次,如果是 10 条记录,则循环运行 11 次,等等。知道这里发生了什么吗?

【问题讨论】:

【参考方案1】:

设置not_found_creadit = 1 的处理程序在FETCH 没有返回任何行时被触发,但是您在执行FETCH 之前检查它的值,因此循环的主体将当FETCH 失败时额外执行一次,然后循环循环在下一次 迭代开始时退出。

重新排列您的代码以在FETCH 之后立即检查变量的值

credit_loop : LOOP 
    FETCH cur_credit INTO vc_customer, dec_amount, vc_status, vc_user_type, vc_emp, vc_note;
    IF not_found_creadit THEN
        CLOSE cur_credit;
        LEAVE credit_loop;
    END IF;
    SELECT vc_customer, dec_amount, vc_status, vc_user_type, vc_emp, vc_note;
    ......
    ......
END LOOP;

另外,考虑将变量的拼写更正为not_found_credit

【讨论】:

【参考方案2】:

你必须正确的类型,因为我写的是默认值(我不知道你在表信用中有什么)。 End If U create table TempTable use

TRUNCATE TempTable;

请重写示例

CREATE CREATE TEMPORARY TABLE TempTable (`Id` int(11) NOT NULL auto_increment,
  `customer_id` int(11) NOT NULL,
  `amount` int(11) NOT NULL,
  `status` varchar(1000) NOT NULL,
  `user_type` int(11) NOT NULL default '0',
  `employee` varchar(1000) NOT NULL,
  PRIMARY KEY  (`customer_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ;");

当然类型不好:)

 DELIMITER $$
    DROP PROCEDURE IF EXISTS CursorX $$
    CREATE PROCEDURE `CursorX`()
    BEGIN    
            DECLARE xCustomerId int(11);  
            DECLARE xStatus   int(11);
            DECLARE xUserType  varchar(255);
            DECLARE xEmployee  varchar(255);
            DECLARE xNote varchar(255);  
            DECLARE i int(11);
            DECLARE recordNotFound INTEGER DEFAULT 0;
            DECLARE cur_credit CURSOR FOR SELECT customer_id, amount, status, user_type, employee, note FROM credit WHERE status = 'approved' AND customer_id = int_cust_id;
            DECLARE CONTINUE HANDLER FOR NOT FOUND SET recordNotFound = 1;

            DROP TEMPORARY TABLE IF EXISTS TempTable;
            CREATE TEMPORARY TABLE TempTable AS(SELECT * FROM credit);

            OPEN cur_credit;
            set not_found_creadit = 0;
            credit_loop: LOOP
            SET i = i +1;
                FETCH cur_credit INTO xCustomerId,xStatus,xUserType,xEmployee,xNote;
                IF not_found_creadit THEN
                    LEAVE credit_loop;
                 END IF;
            END LOOP credit_loop;
            CLOSE cur_credit;
    select * FROM TempTable;

    END $$

【讨论】:

以上是关于MYSQL游标循环,多跑一圈,为啥?的主要内容,如果未能解决你的问题,请参考以下文章

SQL游标怎么循环更新

求一条sql循环语句

sql mysql如何在存储函数中循环选择查询的游标

Python MySQL连接器在游标循环中执行第二条sql语句?

sqlserver中怎样使用游标for循环

sqlserver中怎样使用游标for循环