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永远不会返回空