MySQL 存储过程例子及坑(stored procedure)

DELIMITER $$

DROP PROCEDURE IF EXISTS updateTradeNoByStatus$$
CREATE PROCEDURE updateTradeNoByStatus()
BEGIN
  DECLARE l_tradeNo VARCHAR(20);
  DECLARE l_id VARCHAR(50);
  DECLARE l_new_tradeNo VARCHAR(20);
  DECLARE NO_MORE_RECORD INT DEFAULT 0;
  -- 缓存数据到游标
  DECLARE trade_cur CURSOR FOR SELECT t.id,t.tradeNo FROM trade t WHERE t.status >=3 ORDER BY t.status;
  -- 针对NOT FOUND的条件,当没有记录时赋值为1
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET NO_MORE_RECORD = 1;

  OPEN trade_cur; -- 打开游标
    WHILE NO_MORE_RECORD != 1 DO
      FETCH trade_cur INTO l_id, l_tradeNo;
      # 如果不加判断,会多循环一次。最后一次读取游标时,NO_MORE_RECORD是1,但是进入循环之前是0,故可以进入循环,会多循环一次;
      IF NO_MORE_RECORD != 1 THEN
        -- 查询订单编号
        SELECT concat(nt.tradePre,nt.tradeDate, lpad(nt.tradeFlow,6,'0')) INTO l_new_tradeNo FROM num_table nt WHERE nt.id = 1;
        -- 修改订单编号
        UPDATE trade t2 SET t2.tradeNo = l_new_tradeNo WHERE t2.id = l_id;
        INSERT INTO temp values(l_id,l_new_tradeNo,NO_MORE_RECORD);
        -- 修改订单编号+1
        UPDATE num_table t SET t.tradeFlow=t.tradeFlow+1, t.tradeDate=date_format(now(),'%Y%m') WHERE t.id = 1;
      END IF ;
    END WHILE;
  CLOSE trade_cur; -- 关闭游标

END$$

DELIMITER ;

正常情况这么写是没问题的,可是如果你在while里面的要是有select语句的话就有问题了。如果说你的处理逻辑是这样的:

那么当你的 SELECT concat(nt.tradePre,nt.tradeDate, lpad(nt.tradeFlow,6,'0')) INTO l_new_tradeNo FROM num_table nt WHERE nt.id = 1 找不到数据的时候,DECLARE CONTINUE HANDLER FOR NOT FOUND SET NO_MORE_RECORD = 1; 这句就会执行,有 1 != 1所以循环体会提前跳出。通过测试得出,DECLARE CONTINUE HANDLER FOR NOT FOUND SET NO_MORE_RECORD = 1; 是对全局的 select 有效的,只要有一条 select 语句返回空,那么就是触发该语句。

解决方法就是确保while里面的select永远不会返回空

你可能感兴趣的:(MySQL 存储过程例子及坑(stored procedure))