【问题标题】:MySQL CURSOR loop adds extra pass in stored procedureMySQL CURSOR 循环在存储过程中添加了额外的传递
【发布时间】:2014-03-25 12:02:54
【问题描述】:

我在 mysql 存储过程中遇到游标提取循环问题。我的存储过程运行一个重新排序过程,它工作得很好,直到排序的最后一个记录,其中订单编号跳过一个数字。例如,如果我有 10 条记录并且排序过程从 1 开始,则从 1 到 10 的所有数字都应显示在结果记录中。但是,我的存储过程跳过了最后一个计数,在上面的例子中是 10,并将最后的记录重新编号为 11,因此计数从 9 变为 11。无论涉及的记录数如何,都是这种情况。

程序的逻辑相当简单:

我有一个包含产品类型记录的表,其中有一个 sort_order 列,用于根据常规批处理周期中的使用情况对记录进行重新排序。

CREATE TABLE `PRODUCT_TYPE` (
  `PRODUCT_TYPE_ID` int(11) NOT NULL AUTO_INCREMENT,
  `PRODUCT_TYPE_NAME` varchar(45) NOT NULL,
  `PRODUCT_CATEGORY_ID` int(11) DEFAULT NULL,
  `LIFESPAN_MONTHS` int(11) DEFAULT NULL,
  `USER_ID` int(11) DEFAULT NULL,
  `UPDATED_BY` int(11) DEFAULT NULL,
  `UPDATED_DATE` datetime DEFAULT NULL,
  `CREATED_DATE` datetime DEFAULT NULL,
  `CREATED_BY` int(11) DEFAULT NULL,
  `REVIEWED` bit(1) NOT NULL DEFAULT b'0',
  `SORT_ORDER` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`PRODUCT_TYPE_ID`),
  KEY `fk_PRODUCT_TYPE_PRODUCT_CATEGORY1_idx` (`PRODUCT_CATEGORY_ID`),
  KEY `fk_PRODUCT_TYPE_USERS1_idx` (`USER_ID`),
  KEY `fk_PRODUCT_TYPE_USERS2_idx` (`UPDATED_BY`),
  KEY `fk_PRODUCT_TYPE_USERS3_idx` (`CREATED_BY`),
  CONSTRAINT `fk_PRODUCT_TYPE_PRODUCT_CATEGORY1` FOREIGN KEY (`PRODUCT_CATEGORY_ID`) REFERENCES `PRODUCT_CATEGORY` (`PRODUCT_CATEGORY_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `fk_PRODUCT_TYPE_USERS1` FOREIGN KEY (`USER_ID`) REFERENCES `USERS` (`USER_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `fk_PRODUCT_TYPE_USERS2` FOREIGN KEY (`UPDATED_BY`) REFERENCES `USERS` (`USER_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `fk_PRODUCT_TYPE_USERS3` FOREIGN KEY (`CREATED_BY`) REFERENCES `USERS` (`USER_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=latin1;

我每晚运行以下存储过程,以使用 sort_order 列记录订单,根据对每种类型的引用数对产品类型记录重新排序。

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `REORDER_MANUFACTURERS`()
BEGIN

DECLARE DONE BOOL;
DECLARE MID INT;
DECLARE MNAME VARCHAR(255);
DECLARE USES INT;
DECLARE SORT_ORDER_COUNTER INT;

DECLARE CUR CURSOR FOR SELECT M.MANUFACTURER_ID, M.MANUFACTURER_NAME, COUNT(U.UNIT_ID) AS USES 
FROM MANUFACTURERS M LEFT JOIN mydb.UNITS U ON  M.MANUFACTURER_ID = U.MANUFACTURER_ID
GROUP BY M.MANUFACTURER_ID, M.MANUFACTURER_NAME
ORDER BY USES DESC, MANUFACTURER_NAME;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET DONE = TRUE;

SET SORT_ORDER_COUNTER = 0;

OPEN CUR;

READ_LOOP: LOOP

    FETCH CUR INTO MID, MNAME, USES;

    UPDATE MANUFACTURERS SET SORT_ORDER = SORT_ORDER_COUNTER WHERE MANUFACTURER_ID = MID;

    IF DONE THEN
      LEAVE READ_LOOP;
    END IF;

    SET SORT_ORDER_COUNTER = SORT_ORDER_COUNTER + 1;

END LOOP;

CLOSE CUR;

END

在我的一生中,我找不到这种逻辑会导致计数跳过一个节拍的问题。任何帮助将不胜感激。

【问题讨论】:

    标签: mysql loops stored-procedures cursor


    【解决方案1】:

    改变

    FETCH CUR INTO MID, MNAME, USES;
    
    UPDATE MANUFACTURERS SET SORT_ORDER = SORT_ORDER_COUNTER 
        WHERE MANUFACTURER_ID = MID;
    
    IF DONE THEN
      LEAVE READ_LOOP;
    END IF;
    

    收件人

    FETCH CUR INTO MID, MNAME, USES;
    
    IF DONE THEN
      LEAVE READ_LOOP;
    END IF;
    
    UPDATE MANUFACTURERS SET SORT_ORDER = SORT_ORDER_COUNTER 
        WHERE MANUFACTURER_ID = MID;
    

    因为:

    如果您 FETCH 超过了结果集中的最后一行,则目标字段或变量的值是不确定的,NOTFOUND 属性返回 TRUE

    参考:(这是在Oracle游标上,但也适用于其他游标):

    【讨论】:

      猜你喜欢
      • 2019-01-19
      • 1970-01-01
      • 2013-11-13
      • 1970-01-01
      • 2017-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多