MySQL存储过程执行无返回行 末尾SELECT语句不生效问题
问题描述
作为MySQL存储过程开发新手,尝试在存储过程内的LOOP循环执行完成后返回结果行,初始编写代码如下:
BEGIN DECLARE date_SD date; DECLARE c_stack CURSOR FOR select SD from t4 where date(SD) >= "2022-05-01" and date(SD)<= "2022-05-30" group by SD; DROP TEMPORARY TABLE IF EXISTS final_result; CREATE TEMPORARY TABLE final_result LIKE templaedb.temp_table; OPEN c_stack; read_loop: LOOP FETCH c_stack INTO date_SD; INSERT INTO final_result VALUES ('first','140','2022-05-06','','1','2','3','4','5'); INSERT INTO final_result VALUES ('last','500','2022-05-06','','11','12','13','14','15'); END LOOP read_loop; CLOSE c_stack; select 'Print Test'; select * from final_result; END
执行该存储过程时,过程末尾的SELECT语句无法正常运行,未返回预期结果行。
故障原因
- 游标循环未配置终止判断逻辑:MySQL游标遍历完绑定的结果集后,执行
FETCH会触发1329号NOT FOUND错误,代码中没有定义该错误对应的处理逻辑,存储过程会在触发错误时直接终止,不会执行循环后续的SELECT语句。 - 现有循环逻辑存在冗余问题:循环内INSERT语句的日期值写死为固定值,未使用每次FETCH获取到的
date_SD变量,即使循环正常执行,生成的结果也不符合按查询到的SD日期逐行生成数据的预期。
修复代码
需要提前声明循环终止标记、配置游标遍历结束的异常处理逻辑,在FETCH到末尾时主动跳出循环,再执行后续结果查询。修复后可正常运行的代码如下:
BEGIN -- 声明循环终止标识,默认未终止 DECLARE done INT DEFAULT FALSE; DECLARE date_SD date; -- 声明游标 DECLARE c_stack CURSOR FOR select SD from t4 where date(SD) >= "2022-05-01" and date(SD)<= "2022-05-30" group by SD; -- 游标遍历到结果集末尾时,将终止标识设为TRUE DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; DROP TEMPORARY TABLE IF EXISTS final_result; CREATE TEMPORARY TABLE final_result LIKE templaedb.temp_table; OPEN c_stack; read_loop: LOOP FETCH c_stack INTO date_SD; -- 检测到终止标识时直接跳出循环 IF done THEN LEAVE read_loop; END IF; -- 替换写死的日期为游标取到的实际SD值,符合业务逻辑 INSERT INTO final_result VALUES ('first','140',date_SD,'','1','2','3','4','5'); INSERT INTO final_result VALUES ('last','500',date_SD,'','11','12','13','14','15'); END LOOP read_loop; CLOSE c_stack; SELECT 'Print Test'; SELECT * FROM final_result; END
注意事项
- 存储过程内的声明顺序有严格要求:必须先声明普通变量,再声明游标,最后声明异常处理HANDLER,顺序错误会直接报语法错。
- 所有使用游标做循环遍历的场景,都必须配置
NOT FOUND对应的CONTINUE HANDLER,否则必然会在遍历结束时触发异常中断过程。 - FETCH操作后需要第一时间判断终止标识,不要在标识为终止后再执行业务插入逻辑,避免多插入一条无效脏数据。
内容的提问来源于stack exchange,提问作者Praveen Kumar
相关产品推荐
相关产品推荐

