【问题标题】:Cannot change primary key because of "incorrectly formed foreign key constraint" error由于“格式不正确的外键约束”错误,无法更改主键
【发布时间】:2015-07-15 06:39:38
【问题描述】:

我有一个具有以下架构定义的表:

CREATE TABLE `currency` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `code` char(3) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL
  PRIMARY KEY (`id`),
  UNIQUE KEY `code_UNIQUE` (`code`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

我想要的是删除id 列并将code 作为新的主键。并且其他一些表具有该表的外键。我尝试了以下命令但失败了:

SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE `currency` CHANGE COLUMN `id` `id` INT(11) NOT NULL, DROP PRIMARY KEY;
ALTER TABLE currency ADD PRIMARY KEY (code);
SET FOREIGN_KEY_CHECKS=1;

MySQL 抛出以下异常:

[查询 2 中的错误] 将“./db/#sql-849_1”重命名为“./db/currency”时出错(错误号:150 - 外键约束格式不正确) 执行停止!

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    跑步

    ALTER TABLE myTable DROP PRIMARY KEY;
    

    导致类似

    的错误
    `Error Code: 1025. Error on rename of 'some_name' to 'another_name' (errno: 150 - Foreign key constraint is incorrectly formed)`
    

    删除、创建新列并将其添加为主键全部 作为一个单一的命令就像一个魅力。

    虽然我不知道根本原因,但这是我想出的最终解决方案:

    -- Suppose c1 and c2 are a composite primary key and 
    -- I want to add an incremental primary key named id
    ALTER TABLE myTable 
        DROP PRIMARY KEY, 
        ADD id INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT FIRST, 
        ADD INDEX `an_index_name_for_c1_c2` (`c1`, `c2`);
    

    请注意,为了遗留代码性能,我将以前的复合主键列添加为新的复合索引。

    【讨论】:

      【解决方案2】:

      错误

      重命名错误... errno: 150 - 外键约束格式不正确)

      发生是因为您试图删除引用的主键,即使您正在使用 SET FOREIGN_KEY_CHECKS=0; 禁用外键约束检查

      禁用外键检查将允许您临时删除currency 表中的一行或在外键表中添加无效的currencyId,但不能删除主键。

      更改已被其他表引用的 PRIMARY KEY 并非易事,因为您可能会失去表之间的引用完整性并丢失数据之间的关系。为了保存数据,您需要一个过程,例如:

      • 为每个 FK 表添加一个新的外键列 (code)
      • 通过更新从先前的currencyId 映射code 外键
      • 删除现有的外键
      • 删除旧的currencyId外键列
      • 删除所有 FK 后,更改 currency 表上的主键
      • 根据新的code 列重新建立外键

      下面的操作不需要禁用FOREIGN_KEY_CHECKS,但需要对所有引用currency的表重复外键映射/删除/重新创建步骤:

      -- Add new FK column
      ALTER TABLE FKTable ADD currencyCode char(3) 
                              CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;
      -- Map FK column to the new Primary Key
      UPDATE FKTable
        SET currencyCode = (SELECT `code` FROM currency WHERE id = FKTable.currencyId);
      -- Drop the old foreign key + column
      ALTER TABLE FKTable DROP FOREIGN KEY FKTable_Currency;
      ALTER TABLE FKTable DROP COLUMN currencyId;
      -- Once the above is done for all FK tables, drop the PK on currency
      ALTER TABLE `currency` CHANGE COLUMN `id` `id` INT(11) NOT NULL, 
                                                            DROP PRIMARY KEY;
      ALTER TABLE currency ADD PRIMARY KEY (`code`);
      ALTER TABLE FKTable ADD CONSTRAINT FKTable_Currency2
                FOREIGN KEY (currencyCode) REFERENCES currency(`code`);
      

      SqlFiddle here

      【讨论】:

      • 这对我帮助很大。谢谢。 +1
      • 就我而言,我创建了unique 索引,然后无法删除它。我必须先创建一个 primary 密钥,然后删除唯一的。
      【解决方案3】:

      为什么不

      • 删除外键
      • 删除主键
      • 创建主键
      • 创建外键

      ?

      我不得不承认我现在没有太多流量(没有),只是测试可以轻松恢复的数据,但对我来说效果很好。

      【讨论】:

        猜你喜欢
        • 2019-08-08
        • 1970-01-01
        • 1970-01-01
        • 2020-02-19
        • 2020-11-12
        • 2021-03-01
        • 2014-11-20
        • 1970-01-01
        • 2021-11-07
        相关资源
        最近更新 更多