Cannot change primary key because of "incorrectly formed foreign key constraint" error
The error
Error on rename of ... errno: 150 - Foreign key constraint is incorrectly formed)
happens because you are trying to drop a referenced primary key, even though you are disabling foreign key constraint checking with SET FOREIGN_KEY_CHECKS=0;
Disabling foreign key checks would allow you to temporarily delete a row in the currency
table or add an invalid currencyId
in the foreign key tables, but not to drop the primary key.
Changing a PRIMARY KEY which is already referenced by other tables isn't going to be simple, since you risk losing referential integrity between the tables and losing the relationship between data. In order to preserve the data, you'll need a process such as:
- Add a new Foreign key column (
code
) to each FK table - Map the
code
foreign key from the previouscurrencyId
via an update - Drop the existing foreign key
- Drop the old
currencyId
foreign key column - Once all FK's have been dropped, change the primary key on the
currency
table - Reestablish the foreign keys based on the new
code
column
The below would do this without needing to disable the FOREIGN_KEY_CHECKS
, but the foreign key map / drop / recreate step would need to be repeated for all tables referencing 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
Running
ALTER TABLE myTable DROP PRIMARY KEY;
caused an error like
`Error Code: 1025. Error on rename of 'some_name' to 'another_name' (errno: 150 - Foreign key constraint is incorrectly formed)`
Dropping, creating new column and adding it as a primary key all as a single command works like a charm.
Even though I don't know the root cause, this is the final solution I came up to:
-- 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`);
Note that for sake of legacy code performance, I add previous compound primary key columns as a new compound index.