如何在存储过程中遍历表全量行并逐行调用指定存储过程
问题原因及修复方案
核心问题:NOT FOUND 处理器作用范围溢出
你定义的CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;作用范围是整个外层存储过程,包含你调用的STR_COUNT存储过程里的所有语句:
当STR_COUNT里的UPDATE语句没有匹配到任何行时,MySQL会触发NOT FOUND信号,直接将外层的done变量设为TRUE,导致游标循环执行完第一次就判断到终止条件,直接退出。
其他代码问题
- CASE分支重复无效:
STR_COUNT第一个CASE结构中,第3、4个分支的判断条件完全相同,第4个分支本来要判断pa1="p" and pa2="p"的逻辑永远不会触发。 - 游标查询不严谨:游标使用
SELECT *查询表字段,后续如果表结构变更字段顺序,会直接导致FETCH赋值错位,排查难度很高。
修复方案
1. 调整外层存储过程的循环逻辑,隔离内部NOT FOUND信号
把调用STR_COUNT的逻辑包裹在独立的局部块中,单独处理内部的NOT FOUND信号,避免影响外层游标循环的终止标识:
BEGIN DECLARE done INT DEFAULT FALSE; DECLARE t1 INT default 0; DECLARE t2 INT default 0; DECLARE p1 VARCHAR(2) default ' '; DECLARE p2 VARCHAR(2) default ' '; DECLARE st INT default 0; DECLARE sp INT default 0; DECLARE ce VARCHAR(2) default ' '; DECLARE sgid int; -- 明确指定查询字段,避免表结构变更导致赋值错位 DECLARE Get_cur CURSOR FOR SELECT SEGID, Chrome, strt, stp, TESTID1, TESTID2, Path1, Path2 FROM segments; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; OPEN Get_cur; set done = False; lbl: LOOP FETCH Get_cur INTO sgid, CE, ST, SP, T1, T2, P1, P2; IF done then LEAVE lbl; END IF; -- 新增局部块,隔离内部存储过程的NOT FOUND信号 BEGIN -- 内部的NOT FOUND直接忽略,不修改外层done变量 DECLARE CONTINUE HANDLER FOR NOT FOUND BEGIN END; CALL STR_COUNT(T1,T2,P1,P2,ST,SP,CE); END; -- 额外重置done标识,避免意外修改 SET done = FALSE; END LOOP; CLOSE Get_cur; END
2. 修正STR_COUNT的重复CASE分支
把第一个CASE结构中第四个分支的判断条件修改为正确的逻辑:
-- 原错误写法 -- WHEN pa1="p" and pa2="m" THEN -- 修改为 WHEN pa1="p" and pa2="p" THEN
补充:批量更新触发器不生效的说明
MySQL的行级触发器本身会在批量更新时逐行触发,你之前遇到的批量更新失效问题,大概率也是同样的原因:触发器内调用存储过程时触发了NOT FOUND信号,导致执行提前终止,按照上述方法调整存储过程内的HANDLER逻辑即可解决。
内容的提问来源于stack exchange,提问作者Lance
相关产品推荐
相关产品推荐

