Mysql/Mariadb 游标循环仅在返回空字符串并退出时执行

问题描述 投票:0回答:1

我想对表 good 和 org 以及所有具有这些表外键的表进行部分备份。为此,我编写了两个程序。第一个为使用 CONSTRAINT_COL_NAMECONSTRAINT_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 不会授予文件!)

现在我想调用每个具有 goodorg 外键的表;接下来是第二个程序:


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
过程本身可以触发处理程序标志,但需要至少调用一次才能发生这种情况...

第二个程序有什么问题?

sql mysql stored-procedures mariadb
1个回答
0
投票

问题出在声明的 table_name 变量上。在 MySQL 中,TABLE_NAME 是一个关键字。因此,使用它会导致奇怪的行为。将变量名称更改为 table_name_ 解决了问题。

我通常依靠我的 IDE 以特殊颜色突出显示所有关键字,但出于某种原因,PyCharm 无论如何都不会突出显示它,让我相信使用它是可以的...

© www.soinside.com 2019 - 2024. All rights reserved.