无法更改外键约束中使用的列

the*_*ava 94 mysql

当我试图改变我的桌子时,我收到了这个错误.

Error Code: 1833. Cannot change column 'person_id': used in a foreign key constraint 'fk_fav_food_person_id' of table 'table.favorite_food'
Run Code Online (Sandbox Code Playgroud)

这是我成功运行的CREATE TABLE STATEMENT.

CREATE TABLE favorite_food(
    person_id SMALLINT UNSIGNED,
    food VARCHAR(20),
    CONSTRAINT pk_favorite_food PRIMARY KEY(person_id,food),
    CONSTRAINT fk_fav_food_person_id FOREIGN KEY (person_id)
    REFERENCES person (person_id)
);
Run Code Online (Sandbox Code Playgroud)

然后我试图执行此语句,我得到了上述错误.

ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT;
Run Code Online (Sandbox Code Playgroud)

Dem*_*tic 170

您可以关闭外键检查:

SET FOREIGN_KEY_CHECKS = 0;

/* DO WHAT YOU NEED HERE */

SET FOREIGN_KEY_CHECKS = 1;
Run Code Online (Sandbox Code Playgroud)

请确保不要在生产中使用它并备份.

  • 似乎是非常不安全的解决方案。它是否可能导致数据完整性丢失? (2认同)
  • 此解决方案很棒,如果您在修改数据之前先写锁,然后在完成后解锁,则可以在生产环境中使用它。使用sql文件在尽可能短的时间内进行更改会更好。 (2认同)
  • 您不需要锁,因为“SET FOREIGN_KEY_CHECKS”是会话范围的(其他会话仍将应用 FK 约束)。它非常适合添加/删除“AUTO_INCRMENT”(不会更改实际的列数据类型),但如果您尝试将列数据类型更改为“真实”(例如,从 SMALLINT 到 INT),那么它*不会工作*当 mysql 尝试用新表替换旧表时,将得到合法的“150 FK 约束错误形成”。在这种情况下,请使用已接受的答案。 (2认同)

Mic*_*eim 108

外键字段和引用的类型和定义必须相同.这意味着您的外键不允许更改字段的类型.

一个解决方案是:

LOCK TABLES 
    favorite_food WRITE,
    person WRITE;

ALTER TABLE favorite_food
    DROP FOREIGN KEY fk_fav_food_person_id,
    MODIFY person_id SMALLINT UNSIGNED;
Run Code Online (Sandbox Code Playgroud)

现在你可以改变你的person_id

ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT;
Run Code Online (Sandbox Code Playgroud)

重新创建外键

ALTER TABLE favorite_food
    ADD CONSTRAINT fk_fav_food_person_id FOREIGN KEY (person_id)
          REFERENCES person (person_id);

UNLOCK TABLES;
Run Code Online (Sandbox Code Playgroud)

编辑: 由于评论,上面添加了锁

在执行此操作时,您必须禁止写入数据库,否则可能会导致数据完整性问题.

我在上面添加了一个写锁

除了你自己的(INSERT, UPDATE, DELETE)之外的任何其他会话中的所有写入查询将等到超时或UNLOCK TABLES; 被执行

http://dev.mysql.com/doc/refman/5.5/en/lock-tables.html

编辑2:OP要求更详细地解释"外键字段的类型和定义和引用必须相等.这意味着您的外键不允许更改字段的类型."

MySQL 5.5参考手册:FOREIGN KEY约束

外键和引用键中的相应列必须在InnoDB内部具有类似的内部数据类型,以便可以在不进行类型转换的情况下对它们进行比较.整数类型的大小和符号必须相同.字符串类型的长度不必相同.对于非二进制(字符)字符串列,字符集和排序规则必须相同.

  • 好的,遗憾的是MySQL不支持DDL语句周围的事务.在执行DDL查询之前提交打开事务请参阅http://dev.mysql.com/doc/refman/5.5/en/implicit-commit.html (5认同)
  • 不要忘记为此使用事务。否则您的数据库可能会损坏。 (2认同)
  • 重新创建外键的正确语句是:ALTER TALE favorite_food ADD CONTRAINT fk_fav_food_person_id FOREIGN KEY(person_id)REFERENCES person(id); (2认同)

kur*_*tko 7

就我而言,有必要添加GLOBAL.

SET FOREIGN_KEY_CHECKS = 0;
SET GLOBAL FOREIGN_KEY_CHECKS=0;

/* DO WHAT YOU NEED HERE */

SET FOREIGN_KEY_CHECKS = 1;
SET GLOBAL FOREIGN_KEY_CHECKS=1;
Run Code Online (Sandbox Code Playgroud)