MySQL存储过程游标为空排查:合并ALARM_XX_*表至ALARM_XX_ALL
问题排查与修复
核心问题:WHERE子句逻辑运算符优先级错误
你的游标查询条件中,AND优先级高于OR,导致原条件被错误解析,实际筛选出的表不符合预期,最终游标无数据。
原条件的实际执行逻辑等价于:
WHERE (table_schema = 'db' AND table_name NOT LIKE 'ALARM_XX_2023_01_%' AND table_name NOT LIKE 'ALARM_XX_2023_02_%' AND table_name LIKE 'ALARM_XX_2022%') OR table_name LIKE 'ALARM_XX_2023%'
这会包含所有table_name LIKE 'ALARM_XX_2023%'的表(不管所属库是否为db),同时可能因权限或匹配逻辑问题,导致实际查询结果为空。
修正方案
用括号明确分组逻辑,确保所有条件都基于table_schema = 'db',同时排除指定的2023年1、2月表,保留2022和2023年的其他表:
DELIMITER // drop procedure if exists union_all_tables // CREATE PROCEDURE union_all_tables() BEGIN DECLARE sql_query VARCHAR(1000); DECLARE done INT DEFAULT FALSE; DECLARE table_name VARCHAR(255); -- 修正游标查询的WHERE逻辑,用括号明确分组 DECLARE tables_cursor CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema = 'db' AND (table_name LIKE 'ALARM_XX_2022%' OR table_name LIKE 'ALARM_XX_2023%') AND table_name NOT LIKE 'ALARM_XX_2023_01_%' AND table_name NOT LIKE 'ALARM_XX_2023_02_%'; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; -- 先判断目标表是否存在,避免重复创建报错 IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_schema = 'db' AND table_name = 'ALARM_XX_ALL') THEN CREATE TABLE ALARM_XX_ALL LIKE db.ALARM_XX_2022_03_01; END IF; OPEN tables_cursor; tables_loop: LOOP FETCH tables_cursor INTO table_name; IF done THEN LEAVE tables_loop; END IF; -- 插入语句加上库名,避免默认schema不一致导致表找不到 SET @sql_query = CONCAT('INSERT INTO ALARM_XX_ALL SELECT * FROM db.', table_name); PREPARE stmt FROM @sql_query; EXECUTE stmt; DEALLOCATE PREPARE stmt; END LOOP; CLOSE tables_cursor; SELECT * FROM ALARM_XX_ALL limit 10; END// DELIMITER ;
额外注意事项
- 确认执行存储过程的账号拥有
information_schema.tables的查询权限,以及所有源表的读取权限、目标表的写入权限 - 若源表数据量较大,建议分批插入或添加事务控制,避免锁表影响业务
内容的提问来源于stack exchange,提问作者Hind_Achniri
相关产品推荐
相关产品推荐

