【问题标题】:Drop foreign key only if it exists仅当存在外键时才删除它
【发布时间】:2013-06-14 05:33:57
【问题描述】:

我在 MySQL 数据库中。

我正在这样做,但它不起作用。

ALTER TABLE `object` DROP FOREIGN KEY IF EXISTS `object_ibfk_1`;

我试图把这个 IF EXISTS 放在任何可以的地方。如何在删除之前检查外键是否存在?

【问题讨论】:

  • 如果您的目标只是暂时禁用外键,请在代码前使用SET FOREIGN_KEY_CHECKS=0;,然后使用SET FOREIGN_KEY_CHECKS=1;,而不必放弃它。
  • 这是一个将 DROP FOREIGN KEY IF EXISTS 添加到 MySQL bugs.mysql.com/bug.php?id=5746 的功能请求,但由于无法修复而被关闭

标签: mysql sql foreign-keys


【解决方案1】:

如果您想删除外键(如果存在)并且不想使用过程,您可以这样做(对于 MySQL):

set @var=if((SELECT true FROM information_schema.TABLE_CONSTRAINTS WHERE
            CONSTRAINT_SCHEMA = DATABASE() AND
            TABLE_NAME        = 'table_name' AND
            CONSTRAINT_NAME   = 'fk_name' AND
            CONSTRAINT_TYPE   = 'FOREIGN KEY') = true,'ALTER TABLE table_name
            drop foreign key fk_name','select 1');

prepare stmt from @var;
execute stmt;
deallocate prepare stmt;

如果有外键,我们将alter table语句放入变量中,如果没有,我们放入一个虚拟语句。然后我们执行它。

【讨论】:

    【解决方案2】:

    为了提高可重用性,您确实希望使用存储过程。在所需的数据库上运行此代码一次:

       DROP PROCEDURE IF EXISTS PROC_DROP_FOREIGN_KEY;
        DELIMITER $$
        CREATE PROCEDURE PROC_DROP_FOREIGN_KEY(IN tableName VARCHAR(64), IN constraintName VARCHAR(64))
        BEGIN
            IF EXISTS(
                SELECT * FROM information_schema.table_constraints
                WHERE 
                    table_schema    = DATABASE()     AND
                    table_name      = tableName      AND
                    constraint_name = constraintName AND
                    constraint_type = 'FOREIGN KEY')
            THEN
                SET @query = CONCAT('ALTER TABLE ', tableName, ' DROP FOREIGN KEY ', constraintName, ';');
                PREPARE stmt FROM @query; 
                EXECUTE stmt; 
                DEALLOCATE PREPARE stmt; 
            END IF; 
        END$$
        DELIMITER ;
    

    此后,您可以随时替换:

    ALTER TABLE `object` DROP FOREIGN KEY IF EXISTS `object_ibfk_1`;
    

    用这个:

    CALL PROC_DROP_FOREIGN_KEY('object', 'object_ibfk_1');
    

    无论object_ibfk_1 是否实际存在,您的脚本都应该能够顺利运行。

    很多功劳归功于:http://simpcode.blogspot.com.ng/2015/03/mysql-drop-foreign-key-if-exists.html

    【讨论】:

      【解决方案3】:
      IF EXISTS(
                    SELECT *
                    FROM INFORMATION_SCHEMA.STATISTICS
                    WHERE INDEX_SCHEMA = DATABASE()
                          AND TABLE_NAME='myTable'
                          AND INDEX_NAME = 'myIndex')
              THEN
      
                  ALTER TABLE `myTable` DROP FOREIGN KEY `myForeignKey`;
      
                  ALTER TABLE `myTable` DROP INDEX `myIndex` ;
      
              END IF;
      

      当你创建外键约束时,mysql会自动在被引用的列上创建索引。上面的示例显示了如何检查 INFORMATION_SCHEMA 中的索引,但您可以在 information schema 中查看更多信息。您的索引名称似乎表明它是为 FK 创建的,因此您必须先删除 FK,然后删除索引。如果再次创建外键,mysql 将再次创建索引。它需要一个索引来强制引用完整性,而不必进行表扫描。

      如果您打算创建一个包含同一列的新索引,则必须先创建该索引(此列将用作 FK,是列列表中的第一个为索引指定)。现在您可以重新添加 FK,mysql 将很乐意使用新索引而无需创建另一个索引。

      编辑:要快速查看索引,只需执行 SHOW INDEXES FROM myTable;

      【讨论】:

        【解决方案4】:

        在当前版本的 Mariadb 10.1.26(新的 Mysql)中,您的查询有效:

        键: MUL

        ALTER TABLE `object` DROP FOREIGN KEY IF EXISTS `object_ibfk_1`;
        DESC `object`;
        

        键: <NULL>

        【讨论】:

          【解决方案5】:

          这是DROP FOREIGN KEY IF EXISTS 的解决方法,v10.1.4 之前的 MySQL 和 MariaDB 版本中缺少该解决方法。您也可以将它用于您想要的所有其他语句,这应该取决于 FOREIGN KEY 的存在(例如,SELECT "info: foreign key exists.",如下例所示)。

          -- DROP FOREIGN KEY IF EXISTS
          SELECT
              COUNT(*)
          INTO
              @FOREIGN_KEY_my_foreign_key_ON_TABLE_my_table_EXISTS
          FROM
              `information_schema`.`table_constraints`
          WHERE
              `table_schema` = 'my_database'
              AND `table_name` = 'my_table'
              AND `constraint_name` = 'my_foreign_key'
              AND `constraint_type` = 'FOREIGN KEY'
          ;
          -- SELECT @FOREIGN_KEY_my_foreign_key_ON_TABLE_my_table_EXISTS;
          SET @statement := IF(
              @FOREIGN_KEY_my_foreign_key_ON_TABLE_my_table_EXISTS > 0,
              -- 'SELECT "info: foreign key exists."',
              'ALTER TABLE my_table DROP FOREIGN KEY my_foreign_key',
              'SELECT "info: foreign key does not exist."'
          );
          PREPARE statement FROM @statement;
          EXECUTE statement;
          

          【讨论】:

            【解决方案6】:

            您使用的是哪个数据库??

            如果 SQL 服务器

            if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FKName]') AND      
            parent_object_id = OBJECT_ID('TableName'))
            alter table TableName drop constraint FKName
            

            【讨论】:

            • 我正在使用 MYSQL ,我试图把这个 IF EXISTS 放在任何可以的地方。如何在删除之前检查外键是否存在?
            • 你用的是哪个mysql存储引擎? MYISAM 还是 INNODB?你确定你没有使用 MISAM?
            • AM 在 mysql 中使用 INNODB 存储引擎,我试图把这个 IF EXISTS 放在任何可以的地方。如何在删除之前检查外键是否存在?
            【解决方案7】:

            类似的讨论: How do I drop a foreign key constraint only if it exists in sql server?

            IF (OBJECT_ID('FK_ConstraintName', 'F') IS NOT NULL)
            

            非常有用,这里还没有提到。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2010-10-03
              • 1970-01-01
              • 2021-01-21
              • 2019-07-28
              • 1970-01-01
              • 2021-05-06
              • 1970-01-01
              相关资源
              最近更新 更多