我有一个存储过程,它循环遍历模式(customerinfo)中的所有表,并通过重命名它们以包含日期并将它们复制到另一个模式(customerinfo_bak)来备份它们。
看起来如下
DELIMITER $$
CREATE PROCEDURE backup_tables()
BEGIN
DECLARE DONE INT DEFAULT FALSE;
DECLARE tableName VARCHAR(255);
DECLARE cursorController CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema = 'customerinfo';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET DONE = TRUE;
OPEN cursorController;
CREATE DATABASE IF NOT EXISTS customerinfo_bak;
REPEAT
SET @backup_table = CONCAT('customerinfo_bak.', tableName, '_backup_', DATE_FORMAT(CURDATE(), '%Y%m%d'));
SET @sqlstmt = CONCAT('CREATE TABLE ', @backup_table, ' LIKE customerinfo.', tableName);
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sqlstmt = CONCAT('INSERT INTO ', @backup_table, ' SELECT * FROM customerinfo.', tableName);
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
UNTIL DONE
END REPEAT;
CLOSE cursorController;
END$$
DELIMITER ;
我遇到的问题是 SP 已保存并在我的架构中可见,但是在使用
CALL customerinfo_bak.backup_tables();
调用它时,我收到以下错误:
错误代码:1064。您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,了解在第 1 行“NULL”附近使用的正确语法
我怀疑这与我如何在 PREPARE 部分中使用本地和会话变量有关,基于此 MySQL Error 1064 : close NULL at line 1 Bill Karwin 的回答,但我不明白为什么会出现这个错误将显示为 NULL 语法问题。
如果有人知道我为什么不能打电话给我的 SP,我将不胜感激。
好吧,我找到了答案(感谢 ChatGPT),事实证明这是由于一个非常简单的疏忽造成的。事实上,“tableName”变量没有在循环内填充。当'tableName'为NULL时,与NULL连接会导致NULL,从而导致SQL语法错误。
更正后的代码如下所示:
DELIMITER $$
CREATE PROCEDURE backup_tables()
BEGIN
DECLARE DONE INT DEFAULT FALSE;
DECLARE tableName VARCHAR(255);
DECLARE cursorController CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema = 'customerinfo';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET DONE = TRUE;
OPEN cursorController;
CREATE DATABASE IF NOT EXISTS customerinfo_bak;
REPEAT
FETCH cursorController INTO tableName;
IF NOT DONE THEN
SET @backup_table = CONCAT('customerinfo_bak.', tableName, '_backup_', DATE_FORMAT(CURDATE(), '%Y%m%d'));
SET @sqlstmt = CONCAT('CREATE TABLE ', @backup_table, ' LIKE customerinfo.', tableName);
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
# Prepare and execute INSERT INTO statement
SET @sqlstmt = CONCAT('INSERT INTO ', @backup_table, ' SELECT * FROM customerinfo.', tableName);
PREPARE stmt FROM @sqlstmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
UNTIL DONE
END REPEAT;
CLOSE cursorController;
END$$
DELIMITER ;
变化:
对于任何想要将此方法用作自动备份脚本的人,您可以将其创建为事件,并通过在事件中调用 SP 来安排其定期运行。
CREATE EVENT backup_event
ON SCHEDULE EVERY 1 DAY -- Adjust schedule as needed
DO
CALL backup_tables();