【问题标题】:Mysql calling procedure failed when dynamically alter table in itMysql调用过程在动态更改表时失败
【发布时间】:2017-06-10 05:37:32
【问题描述】:

我想根据表格是否具有特定列来动态更改表格。

我的数据库名称是summer_cms,里面有50多张表。

我想要的如下:

  1. 如果表中有一个名为add_time 的列,那么我想在其中添加一个列add_user_id
  2. 同样,如果找到update_time,我想在表格中添加update_user_id

我知道我应该在创建数据库模式的过程中把它记下来,但是我的数据库已经构建好了,我必须根据需要对其进行更改。

所以我创建了一个程序来做到这一点:

CREATE PROCEDURE ALTER_SUMMER_TABLE()
BEGIN
    DECLARE tableName VARCHAR(64);
    DECLARE exitence VARCHAR(64);

    DECLARE ntable INT;    # number of tables
    DECLARE i INT;         # index
    SET i = 0;

    # get the count of table
    SELECT COUNT(DISTINCT(TABLE_NAME)) INTO ntable FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'summer_cms';

    WHILE i < ntable DO
        # select the specific table name into the variable of `tableName`.
        SELECT TABLE_NAME INTO tableName
        FROM information_schema.COLUMNS
        WHERE TABLE_SCHEMA = 'summer_cms'
        AND COLUMN_NAME = 'add_time'
        LIMIT 1 OFFSET i;

        # alter table, but I get error in this clause.
        ALTER TABLE tableName ADD COLUMN `add_user_id` INT NOT NULL DEFAULT 0 COMMENT 'add user id';

        # check if the table has `update_time`
        SELECT TABLE_NAME INTO exitence
        FROM information_schema.COLUMNS
        WHERE TABLE_SCHEMA = 'summer_cms'
        AND TABLE_NAME = tableName
        AND COLUMN_NAME = 'update_time';

        # add `update_user_id` if `update_time` be found.
        IF exitence THEN
            ALTER TABLE tableName ADD COLUMN `update_user_id` INT NOT NULL DEFAULT 0 COMMENT 'update user id';
        END IF;
        SET i = i + 1;
    END WHILE;
END

但是当我调用这个过程时出现错误。

Procedure execution failed
1146 - Table 'summer_cms.tableName' doesn't exist

谁能告诉我我遗漏了什么或错了什么?任何帮助将不胜感激。

【问题讨论】:

  • 意思是它所说的-尝试使用动态sql。
  • @P.Salmon 通过其他方式,我可以确认变量tableName 已被赋值。我只是不知道为什么会这样。
  • 是的,但在 alter 语句中没有变量替换 - 它认为它正在改变一个名为 tablename 的表。
  • @P.Salmon 你能告诉我如何修复procedure 来解决我的问题吗?任何提示将不胜感激。

标签: mysql procedure


【解决方案1】:

您可以对您的程序进行一些更改,以使其更加精简并解决一些问题。

首先使用光标选择表名而不是使用您使用的两个选择。其次要使用prepared statement来让你动态设置表名...

DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `ALTER_SUMMER_TABLE`()
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE tableName VARCHAR(64);
    declare cur cursor for SELECT TABLE_NAME
                             FROM information_schema.COLUMNS
                            WHERE TABLE_SCHEMA = 'summer_cms'
                            AND COLUMN_NAME = 'add_time';
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    open cur;

    start_loop: loop
        fetch cur into tableName;
        if (done = 1 )THEN
             LEAVE start_loop;
        END IF;
        SET @sql = CONCAT('ALTER TABLE ', tableName,' ADD COLUMN `add_user_id` INT NOT NULL DEFAULT 0 ');
        PREPARE stmt FROM @sql;
        EXECUTE stmt;

    end loop;

    close cur;
END$$
DELIMITER ;

您可以进行一些调整 - 例如,仅获取该列不存在的表名。

【讨论】:

  • 非常感谢。如果您能告诉我我的程序出了什么问题,那将非常有帮助。
  • @paul 我提出的一点,在 cmets 中也是关于 alter table 语句的,如果您想替换表名或列等内容,则必须将语句构建为字符串名字。绑定仅适用于 SQL 中的值(例如,可以绑定第一个 SQL 中的 'add_time' 位,但不能绑定 COLUMN_NAME
【解决方案2】:

这里是一个动态sql的例子

drop procedure if exists alter_table;
delimiter //

CREATE DEFINER=`root`@`localhost`  procedure alter_table()

begin
declare tablename varchar(20);
set tablename = 'u';

set @sqlstmt =  concat('ALTER TABLE ', tableName, ' ADD COLUMN ', char(96), 'add_user_id', char(96), ' INT NOT NULL DEFAULT 0 COMMENT', char(39), 'add user id', char(39),';');
prepare stmt from @sqlstmt;
execute stmt;
deallocate prepare stmt;

end //

delimiter ;

注意我使用了 ascii 反引号和单引号。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-31
    • 2011-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多