如何检测是否在mysql存储过程中添加了外键?

时间:2017-04-23 15:31:08

标签: python mysql stored-procedures

我尝试过以下操作,但由于某种原因,@check参数设置为我试图检查的约束的值,即使约束不存在。

任何想法为什么?

CREATE PROCEDURE AddForeignKey(
    IN constraint_name varchar(64),
    IN foreign_key_column_name varchar(64),
    IN table_name varchar(64),
    IN database_name varchar(64),
    IN foreign_table_key_name varchar(64),
    IN foreign_table_name varchar(64))

BEGIN
    set @sql = CONCAT('ALTER TABLE ', database_name, '.', table_name,
            ' ADD CONSTRAINT ', constraint_name,
                ' FOREIGN KEY (', foreign_key_column_name, ')'
                ' REFERENCES ', foreign_table_name, ' (', foreign_table_key_name, ');' ) ;

    set @dbname = database_name;

    set @fkname = constraint_name;

    set @check = '';

    SELECT 
        CONSTRAINT_NAME
    INTO
        @check
    FROM 
        INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
    WHERE
       CONSTRAINT_SCHEMA = @dbname
    AND
       CONSTRAINT_NAME   = @fkname
    AND
       CONSTRAINT_TYPE   = 'FOREIGN KEY'
    LIMIT 1;

    IF @check != @fkname
    THEN
        prepare stmt from @sql;
        execute stmt;
    ELSE
        insert into errors(message) values (CONCAT ( 'Check: ', @check, ' DB:', @dbname, ' FK:', @fkname, ' Could not execute statement: ',  @sql));
    END IF;
END

1 个答案:

答案 0 :(得分:1)

您只是比较了CONSTRAINT_NAME列,这不足以防止外键重复创建。

您必须添加REFERENTIAL_CONSTRAINTS表并添加更多列才能进行比较。

此外,我更改了变量名称以避免不必要的变量名称:

CREATE PROCEDURE AddForeignKey(
    IN p_constraint_name varchar(64),
    IN foreign_key_column_name varchar(64),
    IN p_table_name varchar(64),
    IN p_database_name varchar(64),
    IN foreign_table_key_name varchar(64),
    IN foreign_table_name varchar(64))

BEGIN
    set @sql = CONCAT('ALTER TABLE `', p_database_name, '`.`', p_table_name,
        '` ADD CONSTRAINT `', p_constraint_name,
            '` FOREIGN KEY (`', foreign_key_column_name, '`)'
            ' REFERENCES `', foreign_table_name, '` (`', foreign_table_key_name, '`);' ) ;

    set @check = '';

    SELECT 
        TABLE_CONSTRAINTS.CONSTRAINT_NAME
        INTO @check
    FROM 
    INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
            INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
            ON  TABLE_CONSTRAINTS.CONSTRAINT_SCHEMA = REFERENTIAL_CONSTRAINTS.CONSTRAINT_SCHEMA
              AND TABLE_CONSTRAINTS.CONSTRAINT_NAME = REFERENTIAL_CONSTRAINTS.CONSTRAINT_NAME
              AND TABLE_CONSTRAINTS.TABLE_NAME = REFERENTIAL_CONSTRAINTS.TABLE_NAME

    WHERE
    TABLE_CONSTRAINTS.CONSTRAINT_SCHEMA =  p_database_name
        AND TABLE_CONSTRAINTS.CONSTRAINT_NAME   =  p_constraint_name
        AND TABLE_CONSTRAINTS.CONSTRAINT_TYPE   = 'FOREIGN KEY'
    AND TABLE_CONSTRAINTS.TABLE_NAME = p_table_name
        and REFERENTIAL_CONSTRAINTS.REFERENCED_TABLE_NAME = foreign_table_name
    LIMIT 1;

    IF @check <> p_constraint_name
    THEN
        prepare stmt from @sql;
        execute stmt;
    ELSE
        insert into errors(message) values (CONCAT ( 'Check: ', @check, ' DB:', @dbname, ' FK:', 
        @fkname, ' Could not execute statement: ',  @sql));
    END IF;

END