-- 1. 聲明
DECLARE cursor_name CURSOR FOR SELECT 语句;
-- 2. 打開
OPEN cursor_name;
-- 3. 推進/取值
FETCH cursor_name INTO var1, var2...;
-- 4. 關閉
CLOSE cursor_name;
注意:SELECT 不能含 INTO 子句;需聲明 NOT FOUND 條件處理器避免越界報錯。
業務按月分表:student_202301 ~ student_202312,需為每張表同步建立 5 條索引。
DROP PROCEDURE IF EXISTS BatchAddIndex;
DELIMITER $$
CREATE PROCEDURE BatchAddIndex()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tbl_name VARCHAR(64);
-- 聲明游標:查詢前綴為 student_ 的表
DECLARE cur CURSOR FOR
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'front'
AND TABLE_NAME LIKE 'student%';
-- 邊界處理:游標耗盡設置 done=TRUE
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO tbl_name;
IF done THEN
LEAVE read_loop;
END IF;
-- 動態構建 5 條建索引 SQL
SET @sql1 = CONCAT('CREATE INDEX idx_flag ON `', tbl_name, '` (flag)');
SET @sql2 = CONCAT('CREATE INDEX idx_state ON `', tbl_name, '` (state)');
SET @sql3 = CONCAT('CREATE INDEX idx_upload ON `', tbl_name, '` (upload)');
SET @sql4 = CONCAT('CREATE INDEX idx_lockflag ON `', tbl_name, '` (lockFlag)');
SET @sql5 = CONCAT('CREATE INDEX idx_comes ON `', tbl_name, '` (comes)');
-- 預處理 + 執行 + 釋放(逐條執行,便於定位失敗)
PREPARE s1 FROM @sql1; EXECUTE s1; DEALLOCATE PREPARE s1;
PREPARE s2 FROM @sql2; EXECUTE s2; DEALLOCATE PREPARE s2;
PREPARE s3 FROM @sql3; EXECUTE s3; DEALLOCATE PREPARE s3;
PREPARE s4 FROM @sql4; EXECUTE s4; DEALLOCATE PREPARE s4;
PREPARE s5 FROM @sql5; EXECUTE s5; DEALLOCATE PREPARE s5;
END LOOP;
CLOSE cur;
END $$
DELIMITER ;
CALL BatchAddIndex();
存儲過程中變量不能直接作為表名/列名使用,必須動態拼接 SQL 字符串,再通過預處理執行。
CONTINUE:游標結束後繼續執行後續邏輯(本例適用)EXIT:直接退出當前 BEGIN...END 塊pt-online-schema-changeALTER TABLE ... ADD COLUMN ...ALTER TABLE ... CONVERT TO CHARSET utf8mb4DROP INDEX ... ON ...information_schema.SCHEMATA 雙層循環游標 + 預處理 = MySQL 服務端動態批量 DDL 的標準解法。
威力巨大,風險同在。**生產環境三思而後行,預演環境全流程驗證。**