我想对表 good 和 org 以及所有具有这些表外键的表进行部分备份。为此,我编写了两个程序。第一个为使用 CONSTRAINT_COL_NAME 和 CONSTRAINT_COL_VALUES 中的值过滤的给定 table_name 中的数据生成插入语句。当单独调用时,此过程按预期工作:
最小可重现数据库:
CREATE TABLE good(
id SERIAL PRIMARY KEY,
name VARCHAR(255)
);
CREATE TABLE some_table_1(
id SERIAL PRIMARY KEY,
name VARCHAR(255),
good_id INTEGER REFERENCES good(id)
);
CREATE TABLE some_table_2(
id SERIAL PRIMARY KEY,
name VARCHAR(255),
good_id INTEGER REFERENCES good(id)
);
CREATE TABLE org(
id SERIAL PRIMARY KEY,
name VARCHAR(255)
);
CREATE TABLE some_table_3(
id SERIAL PRIMARY KEY,
name VARCHAR(255),
org_id INTEGER REFERENCES org(id)
);
CREATE TABLE some_table_4(
id SERIAL PRIMARY KEY,
name VARCHAR(255),
good_id INTEGER REFERENCES good(id),
org_id INTEGER REFERENCES org(id)
);
-- Example data:
INSERT INTO good(name) VALUES ('good 1'), ('good 2'), ('good 3');
INSERT INTO org(name) VALUES ('org 1'), ('org 2'), ('org 3');
INSERT INTO some_table_1(name, good_id) VALUES ('some_table_1 1', 1), ('some_table_1 2', 2), ('some_table_1 3', 3);
INSERT INTO some_table_2(name, good_id) VALUES ('some_table_2 1', 1), ('some_table_2 2', 2), ('some_table_2 3', 3);
INSERT INTO some_table_3(name, org_id) VALUES ('some_table_3 1', 1), ('some_table_3 2', 2), ('some_table_3 3', 3);
INSERT INTO some_table_4(name, good_id, org_id) VALUES ('some_table_4 1', 1, 1), ('some_table_4 2', 2, 2), ('some_table_4 3', 3, 3);
程序1:
DELIMITER $$
DROP PROCEDURE IF EXISTS GenerateInsertStatements;
CREATE PROCEDURE GenerateInsertStatements(IN table_name VARCHAR(64), IN CONSTRAINT_COL_NAME VARCHAR(64), IN CONSTRAINT_COL_VALUES VARCHAR(4096))
BEGIN
DECLARE col_list TEXT DEFAULT '';
DECLARE col_list_quoted TEXT DEFAULT '';
-- Construct the comma-separated list of column names
SELECT
GROUP_CONCAT(cols.COLUMN_NAME ORDER BY cols.ORDINAL_POSITION),
GROUP_CONCAT(CONCAT('QUOTE(', cols.COLUMN_NAME, ')') ORDER BY cols.ORDINAL_POSITION)
INTO
col_list,
col_list_quoted
FROM
INFORMATION_SCHEMA.COLUMNS as cols
WHERE
cols.TABLE_NAME = table_name
AND TABLE_SCHEMA = DATABASE();
-- Construct the SQL to generate INSERT statements for each row in the table
SET @sql_ = CONCAT(
'SELECT CONCAT(''INSERT INTO ', table_name, ' (', col_list, ') VALUES ('', ',
'CONCAT_WS('','', ', col_list_quoted, '), '')'','''') AS insert_statements
INTO OUTFILE ''/var/lib/mysql-files/export_data_',table_name, '.txt'' LINES TERMINATED BY ''\n''
FROM ', table_name, ' ',
'WHERE ', CONSTRAINT_COL_NAME, ' IN (', CONSTRAINT_COL_VALUES, ');'
);
-- Prepare and execute the SQL
PREPARE stmt FROM @sql_;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;
调用
call GenerateInsertStatements('some_table_1', 'good_id', '2,3');
按预期工作,并在 /var/lib/mysql-files/ 处生成一个文件(注意* 您的用户必须授予其 FILE。以 root 或授予 FILE 的用户身份运行 - GRANT ALL 不会授予文件!)
现在我想调用每个具有 good 或 org 外键的表;接下来是第二个程序:
DELIMITER $$
DROP PROCEDURE IF EXISTS export_inserts;
CREATE PROCEDURE export_inserts()
BEGIN
DECLARE good_ids VARCHAR(4096) DEFAULT '2,3';
DECLARE org_ids VARCHAR(4096) DEFAULT '1,2';
DECLARE table_name VARCHAR(64);
DECLARE done INT DEFAULT 0;
# Tables that reference good:
DECLARE cursor_for_good_referees CURSOR FOR
SELECT DISTINCT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME IN ('good_id') AND TABLE_SCHEMA = DATABASE();
# Tables that reference org:
DECLARE cursor_for_org_referees CURSOR FOR
SELECT DISTINCT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME IN ('org_id') AND TABLE_SCHEMA = DATABASE();
-- Handler for when there are no more rows
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET done = 1;
--
-- GET ALL GOOD RELATED TABLES
--
open cursor_for_good_referees;
read_loop_1: LOOP
FETCH cursor_for_good_referees INTO table_name;
IF done = 1 THEN
LEAVE read_loop_1;
END IF;
SELECT CONCAT('Debug inside loop 1. table_name = ', table_name);
IF table_name IS NOT NULL THEN
select 'call';
call GenerateInsertStatements(table_name, 'good_id', good_ids);
END IF;
END LOOP read_loop_1;
-- Close the cursor
CLOSE cursor_for_good_referees;
--
-- GET ALL ORG RELATED TABLES
--
set done = 0;
open cursor_for_org_referees;
read_loop_2: LOOP
FETCH cursor_for_org_referees INTO table_name;
IF done = 1 THEN
LEAVE read_loop_2;
END IF;
SELECT concat('Debug inside loop 2. table_name = ', table_name);
IF table_name THEN
call GenerateInsertStatements(table_name, 'org_id', org_ids);
END IF;
END LOOP read_loop_2;
-- Close the cursor
CLOSE cursor_for_org_referees;
END $$
DELIMITER ;
call export_inserts();
这仅进入循环一次,table_name 是一个空字符串。
我的光标处理程序做错了什么吗?
理论上,
GenerateInsertStatements
过程本身可以触发处理程序标志,但需要至少调用一次才能发生这种情况...
第二个程序有什么问题?
问题出在声明的 table_name 变量上。在 MySQL 中,TABLE_NAME 是一个关键字。因此,使用它会导致奇怪的行为。将变量名称更改为 table_name_ 解决了问题。
我通常依靠我的 IDE 以特殊颜色突出显示所有关键字,但出于某种原因,PyCharm 无论如何都不会突出显示它,让我相信使用它是可以的...