MySQL 错误 1215:无法添加外键约束

Posted

技术标签:

【中文标题】MySQL 错误 1215:无法添加外键约束【英文标题】:MySQL Error 1215: Cannot add foreign key constraint 【发布时间】:2013-06-02 20:56:54 【问题描述】:

我正在尝试将我的新架构转发到我的数据库服务器上,但我无法弄清楚为什么会出现此错误。

我试图在这里搜索答案,但我发现的所有内容都表明要么将数据库引擎设置为 InnoDB,要么确保我尝试用作外键的键是他们自己的桌子。如果我没记错的话,这两件事我都做过。我还能做什么?

Executing SQL script in server

ERROR: Error 1215: Cannot add foreign key constraint

-- -----------------------------------------------------
-- Table `Alternative_Pathways`.`Clients_has_Staff`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `Alternative_Pathways`.`Clients_has_Staff` (
  `Clients_Case_Number` INT NOT NULL ,
  `Staff_Emp_ID` INT NOT NULL ,
  PRIMARY KEY (`Clients_Case_Number`, `Staff_Emp_ID`) ,
  INDEX `fk_Clients_has_Staff_Staff1_idx` (`Staff_Emp_ID` ASC) ,
  INDEX `fk_Clients_has_Staff_Clients_idx` (`Clients_Case_Number` ASC) ,
  CONSTRAINT `fk_Clients_has_Staff_Clients`
    FOREIGN KEY (`Clients_Case_Number` )
    REFERENCES `Alternative_Pathways`.`Clients` (`Case_Number` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_Clients_has_Staff_Staff1`
    FOREIGN KEY (`Staff_Emp_ID` )
    REFERENCES `Alternative_Pathways`.`Staff` (`Emp_ID` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB

SQL 脚本执行完成:语句:7 条成功,1 条失败

这是父表的 SQL。

CREATE  TABLE IF NOT EXISTS `Alternative_Pathways`.`Clients` (
  `Case_Number` INT NOT NULL ,
  `First_Name` CHAR(10) NULL ,
  `Middle_Name` CHAR(10) NULL ,
  `Last_Name` CHAR(10) NULL ,
  `Address` CHAR(50) NULL ,
  `Phone_Number` INT(10) NULL ,
  PRIMARY KEY (`Case_Number`) )
ENGINE = InnoDB

CREATE  TABLE IF NOT EXISTS `Alternative_Pathways`.`Staff` (
  `Emp_ID` INT NOT NULL ,
  `First_Name` CHAR(10) NULL ,
  `Middle_Name` CHAR(10) NULL ,
  `Last_Name` CHAR(10) NULL ,
  PRIMARY KEY (`Emp_ID`) )
ENGINE = InnoDB

【问题讨论】:

记住 unsigned 会影响类型。 【参考方案1】:

您还可以检查两个表的引擎是否都设置为 InnoDB。

【讨论】:

【参考方案2】:

对我来说,1215 错误发生在我导入由mysqldump 创建的转储文件时,它按字母顺序创建表,在我的情况下,这导致外键引用文件中稍后创建的表。 (对此博客文章的提示:MySQL Error Code 1215: “Cannot add foreign key constraint”

由于 mysqldump 按字母顺序排列表并且我不想更改表的名称,因此我按照 JeremyWeir on this page 的答案中的说明进行操作,其中指出将 set FOREIGN_KEY_CHECKS = 0; 放在转储文件的顶部并放入 @转储文件底部的 987654325@。

那个解决方案对我有用。

【讨论】:

【参考方案3】:

检查表格的排序规则。使用SHOW TABLE STATUS,您可以检查有关表的信息,包括排序规则。

两个表必须具有相同的排序规则。

这件事发生在我身上。

【讨论】:

这是我的问题 - MySQL 错误根本没有帮助!【参考方案4】:

检查与SHOW TABLE STATUS WHERE Name = 'tableName' 的表兼容性(引擎)。

例如,如果一张桌子是MyISAM,另一张桌子是InnoDB,你可能会遇到这个问题。

你可以通过这个命令来改变它:

ALTER TABLE myTable ENGINE = InnoDB;

From documentation.

【讨论】:

【参考方案5】:

对于 MySQL (InnoDB) ...获取要链接的列的定义:

SELECT * FROM information_schema.columns WHERE
TABLE_NAME IN (tb_name','referenced_table_name') AND
COLUMN_NAME  IN ('col_name','referenced_col_name')\G

比较并验证两个列定义具有:

相同的 COLUMN_TYPE(长度),相同的 COLATION

可能需要禁用/启用 foreign_key 机制,但要注意是否在生产环境中:

set foreign_key_checks=0;
ALTER TABLE tb_name ADD FOREIGN KEY(col_name) REFERENCES ref_table(ref_column) ON DELETE ...
set foreign_key_checks=1;

【讨论】:

【参考方案6】:

此错误的另一个来源是当您有两个或多个具有相同外键名称的相同表名时。

这有时会发生在使用建模和设计软件(如 MySQL Workbench)并随后从设计中生成脚本的人身上。

【讨论】:

【参考方案7】:

我遇到此错误的原因完全不同。我使用MySQL Workbench 6.3 来创建我的数据模型(很棒的工具)。我注意到当外键约束定义中定义的列顺序不符合表列顺序时,也会产生这个错误。

除了检查之外,我花了大约四个小时尝试其他所有方法。

现在一切正常,我可以回去编码了。 :-)

【讨论】:

你这是什么意思? @YazanJaber 我认为他的意思是this:InnoDB 允许外键引用任何索引列或列组。但是,在被引用的表中,必须有一个索引,其中被引用的列按相同顺序列为第一列。【参考方案8】:

也要注意反引号的使用。我在脚本中有以下语句

ALTER TABLE service ADD FOREIGN KEY (create_by) REFERENCES `system_user(id)`;

但最后的反引号是错误的。应该是:

ALTER TABLE service ADD FOREIGN KEY (create_by) REFERENCES `system_user`(`id`);

遗憾的是,MySQL 没有提供有关此错误的任何详细信息...

【讨论】:

【参考方案9】:

当列的类型不同时也会发生这种情况。

例如,如果您引用的列是 UNSIGNED INT,而引用的列是 INT,那么您会收到此错误。

【讨论】:

【参考方案10】:

哇,我刚收到!它混合了许多已经发布的答案(InnoDB、未签名等)。

我在这里没有看到的一件事是:如果您的外键指向主键,请确保源列具有有意义的值。例如,如果主键是 mediumint(8),请确保源列也包含 mediumint(8)。这对我来说是问题的一部分。

【讨论】:

【参考方案11】:

我遇到了同样的问题,我的解决方案是:

之前:

CREATE TABLE EMPRES
( NoFilm smallint NOT NULL

  PRIMARY KEY (NoFilm)

  FOREIGN KEY (NoFilm) REFERENCES cassettes

);

解决方案:

CREATE TABLE EMPRES
(NoFilm smallint NOT NULL REFERENCES cassettes,

 PRIMARY KEY (NoFilm)

);

【讨论】:

您在第一个 CREATE 中忘记了几个逗号【参考方案12】:

当由于引用的表使用 MyISAM 引擎而发生此错误时,此答案提供了一种快速转换数据库的方法,因此所有 Django 模型表都使用 InnoDB:Converting an existing MyISAM database to InnoDB with Django

这是一个名为 convert_to_innodb 的 Django 管理命令。

【讨论】:

【参考方案13】:

对于其他人,相同的错误可能并不总是由于列类型不匹配。您可以通过发出命令找到有关 MySQL 外键错误的更多信息

SHOW ENGINE INNODB STATUS;

您可能会在打印的消息顶部附近发现错误。类似的东西

在引用的表中找不到索引 引用的列显示为第一列或列类型 表中和引用表中的约束不匹配。

【讨论】:

这应该如何工作?连续执行两个查询? @C4u,是的,我们应该通过先显示引擎 INNODB 状态,然后再执行其他查询来连续执行两个查询 phpMyAdmin 上这样做是行不通的。在命令提示符下执行。 "您需要(至少一个)此操作的 PROCESS 权限"【参考方案14】:

我遇到了同样的问题。

我解决了这个问题:

我在 primary key: (id int(11) unsigned NOT NULL AUTO_INCREMENT)

我尝试在我的架构生成器中导入表后发现了这个解决方案。

【讨论】:

【参考方案15】:

在使用 Laravel 4 时,我遇到了“错误 1215:无法添加外键约束”的陷阱,尤其是在使用 JeffreyWay 的 Laravel 4 生成器时。

在 Laravel 4 中,您可以使用 JeffreyWay 的 Generators 生成迁移文件来一张一张地创建表,也就是说,每个迁移文件都会生成一张表。

您必须注意,每个迁移文件的生成都带有文件名中的时间戳,从而为文件提供了顺序。当您触发 Artisan CLI 命令php artisan migrate 时,生成顺序也是迁移操作的顺序。

因此,如果文件要求外键约束引用将在后一个文件中生成但尚未生成的键,则会触发 错误 1215

在这种情况下,您必须调整迁移文件的生成顺序。按顺序生成新文件,将内容拷贝进去,然后删除乱七八糟的旧文件。

【讨论】:

【参考方案16】:

我在尝试添加外键时遇到了同样的错误。就我而言,问题是由外键表的主键标记为无符号引起的。

【讨论】:

【参考方案17】:

可能出现外键约束错误的原因:

    您没有使用 InnoDB 作为所有表的引擎。 您正试图引用目标表上不存在的键。确保它是另一个表上的 (它可以是主键或唯一键,或者只是一个 key) 列的类型不相同(例外是引用表上的列可以为空,即使它在被引用表中不可为空)。 如果主键或外键是 varchar,请确保两者的排序规则相同。 其中一个原因也可能是您用于ON DELETE SET NULL 的列未定义为空。因此,请确保该列设置为默认 null。

检查这些。

【讨论】:

我只是补充一点,如果 FK 在字符列上,我认为它们需要具有相同的字符集和排序规则。 (或者可能 1 字节和 2 字节字符集不兼容。) 伟大而简单的答案!大家调试错误1215应该从这里开始。 I added some more subtle cases to look out for,以防您的错误不是由这些点引起的。 我的原因是你指出的第一个“两个表的不同数据库引擎,InnoDB 和 MyISAM” 我还有一个原因 =) ``` ON DELETE CASCADE ON UPDATE SET NULL:``` 你已经定义了一个 SET NULL 条件,尽管有些列被定义为 NOT NULL。所以,我只是修复 FK 定义。 目标字段没有索引也可能失败。【参考方案18】:

在使用 Laravel 迁移时尝试创建外键时,例如以下示例:

用户表

public function up()

    Schema::create('flights', function (Blueprint $table) 
        $table->increments('id');
        $table->string('name');
        $table->TinyInteger('color_id')->unsigned();
        $table->foreign('color_id')->references('id')->on('colors');
        $table->timestamps();
    );

颜色表

public function up()

    Schema::create('flights', function (Blueprint $table) 
        $table->increments('id');
        $table->string('color');
        $table->timestamps();
    );

有时属性不起作用:

[PDOException]
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint

发生此错误是因为[用户表]中的外键(类型)与[颜色表]中的主键(类型)不同。

要解决这个问题,你应该改变[颜色表]中的主键:

$table->tinyIncrements('id');


当你使用主键$table->Increments('id');时,你应该使用Integer作为外键:

$table->unsignedInteger('fk_id');
$table->foreign('fk_id')->references('id')->on('table_name');

当您使用主键$table->tinyIncrements('id'); 时,您应该使用unsignedTinyInteger 作为外键:

$table->unsignedTinyInteger('fk_id');
$table->foreign('fk_id')->references('id')->on('table_name');

当您使用主键$table->smallIncrements('id'); 时,您应该使用unsignedSmallInteger 作为外键:

$table->unsignedSmallInteger('fk_id');
$table->foreign('fk_id')->references('id')->on('table_name');

当您使用主键$table->mediumIncrements('id'); 时,您应该使用unsignedMediumInteger 作为外键:

$table->unsignedMediumInteger('fk_id');
$table->foreign('fk_id')->references('id')->on('table_name');

【讨论】:

这对我有帮助。我有bigIncrements作为主键,所以我需要使用unsignedBigInteger【参考方案19】:

除了前面所有关于确保字段定义相同且表类型也具有相同排序规则的建议外,请确保您不会犯新手错误,即尝试将 child 字段不在 parent 字段中。如果您在 child 字段中有您尚未输入到 parent 字段中的数据,那么这将导致此错误。很遗憾,错误消息没有更多帮助。

如果不确定,请备份有外键的表,删除所有数据,然后尝试创建外键。如果成功了,你就知道该怎么做了!

【讨论】:

【参考方案20】:

所以我尝试了上述所有修复,但没有运气。我可能在我的表格中遗漏了错误 - 只是找不到原因,我一直收到错误 1215。所以我使用了这个修复程序。

在 phpMyAdmin 的本地环境中,我从相关表中导出了数据。我选择了 CSV 格式。在选择表的 phpMyAdmin 中时,我选择了“更多->选项”。在这里,我向下滚动到“将表复制到(database.table)。选择“仅结构”。重命名表,也许只是在当前表名旁边添加“复制”一词。单击“开始”这将创建一个新的表。导出新表并将其导入新的或其他服务器。我也在此处使用 phpMyAdmin。导入后,将表的名称更改回其原始名称。选择新表,选择导入。格式选择 CSV .取消选中“启用外键检查”。选择“Go”。到目前为止一切正常。

我在blog 上发布了我的修复。

【讨论】:

【参考方案21】:

我只是想为VARCHAR 外键关系添加这种情况。上周我试图在 MySQL Workbench 8.0 中解决这个问题,最终能够修复错误。

简答: 模式、表、列、引用表、引用列以及引用父表的任何其他表的字符集和排序规则必须匹配。

长答案: 我的表中有一个 ENUM 数据类型。我将其更改为VARCHAR,我可以从参考表中获取值,这样我就不必更改父表来添加其他选项。这种外键关系看起来很简单,但我得到了 1215 错误。 arvind的回答和下面的link建议使用

SHOW ENGINE INNODB STATUS;

在使用此命令时,我得到了以下关于错误的详细描述,但没有其他有用信息

在引用的表中找不到索引 引用的列显示为第一列或列类型 表中和引用表中的约束不匹配。 注意 ENUM 和 SET 的内部存储类型在 使用 >= InnoDB-4.1.12 创建的表,以及旧表中的此类列 不能被新表中的此类列引用。 正确的外键定义请参考http://dev.mysql.com/doc/refman/8.0/en/innodb-foreign-key-constraints.html

之后我按照Arvind Bharadwaj 和链接here 的建议使用了SET FOREIGN_KEY_CHECKS=0;

这给出了以下错误消息:

错误代码:1822。添加外键约束失败。失踪 约束索引

此时,我对架构进行了“逆向工程”,并且能够在 EER 图中建立外键关系。在“正向工程师”中,我收到以下错误:

错误 1452:无法添加或更新子行:外键约束 失败

当我将 EER 图“正向工程化”为新模式时,SQL 脚本运行没有问题。在比较尝试进行正向工程生成的 SQL 时,我发现不同之处在于字符集和排序规则。父表、子表和两列具有utf8mb4 字符集和utf8mb4_0900_ai_ci 排序规则,但是,父表中的另一列使用CHARACTER SET = utf8 , COLLATE = utf8_bin ; 引用到不同的子表。

对于整个架构,我将所有表和所有列的字符集和排序规则更改为以下内容:

CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;

这终于解决了我的 1215 错误问题。

旁注: 排序规则utf8mb4_general_ci 适用于 MySQL Workbench 5.0 或更高版本。排序规则utf8mb4_0900_ai_ci 仅适用于 MySQL Workbench 8.0 或更高版本。我相信我遇到字符集和排序规则问题的原因之一是 MySQL Workbench 升级到 8.0 之间。这是一个link,更多地讨论了这个排序规则。

【讨论】:

【参考方案22】:

在我的情况下,我不得不禁用 FOREIGN KEY 检查,因为源表不存在。

SET FOREIGN_KEY_CHECKS=0;

【讨论】:

【参考方案23】:

这是已经说过的一个微妙版本,但在我的例子中,我有 2 个数据库(foo 和 bar)。我首先创建了 foo,但我没有意识到它引用了 bar.baz 中的外键(尚未创建)。当我尝试创建 bar.baz (没有任何外键)时,我不断收到此错误。看了一会,在 foo 中找到了外键。

所以,长话短说,如果您收到此错误,您可能有一个预先存在的外键到正在创建的表。

【讨论】:

【参考方案24】:

另一个原因:如果您使用ON DELETE SET NULL所有列,则外键中使用的列必须允许空值。其他人在this question 中发现了这一点。

据我了解,这在数据完整性方面不会有问题,但似乎 MySQL 不支持此功能(在 5.7 中)。

【讨论】:

【参考方案25】:

就我而言,我使用SET FOREIGN_KEY_CHECKS=0 删除了一个表,然后使用SET FOREIGN_KEY_CHECKS=1。当我去重新加载表格时,我得到了error 1215。问题是数据库中有另一个表具有我已删除并正在重新加载的表的外键。重新加载过程的一部分涉及更改其中一个字段的数据类型,这使另一个表中的外键无效,从而触发error 1215。我通过删除并重新加载另一个表并使用相关字段的新数据类型解决了这个问题。

【讨论】:

【参考方案26】:

对我来说是列类型。大整数!= 整数。

但后来还是不行。

所以我检查了引擎。确保 Table1 = InnoDB 和 Table = InnoDB

【讨论】:

【参考方案27】:

错误 1215 是一个令人讨厌的错误。 Explosion Pill's answer 涵盖了基础知识。你要确保从那里开始。但是,还有更多、更微妙的情况需要注意:

例如,当您尝试链接不同表的 PRIMARY KEY 时,请确保提供正确的 ON UPDATEON DELETE 选项。例如:

...
PRIMARY KEY (`id`),
FOREIGN KEY (`id`) REFERENCES `t` (`other_id`) ON DELETE SET NULL
....

不会飞,因为主键(例如id)不能是NULL

我敢肯定,在添加此类约束时,还会出现更多类似的微妙问题,这就是为什么在遇到约束错误时,请始终确保约束及其含义在您当前的上下文中有意义。祝你的错误 1215 好运!

【讨论】:

如果您尝试删除不存在的外键,您也会收到此错误:) 另外,来自文档:MySQL 需要外键和引用键的索引,以便外键检查可以快速且不需要表扫描。在引用表中,必须有一个索引,其中外键列被列为以相同顺序的第一列。如果引用表不存在,则会在引用表上自动创建此类索引。如果您创建另一个可用于强制外键约束的索引,则此索引可能会在稍后被静默删除。 index_name,如果给定,则如前所述使用。 这就是我来这里的原因:我试图在我想成为NOT NULL 的列上创建一个外键ON DELETE SET NULL。假设你不能一边吃蛋糕一边吃。【参考方案28】:

我找不到这个错误

CREATE TABLE RATING (

Riv_Id INT(5),
Mov_Id INT(10) DEFAULT 0,
Stars INT(5),
Rating_date DATE, 

PRIMARY KEY (Riv_Id, Mov_Id),

FOREIGN KEY (Riv_Id) REFERENCES REVIEWER(Reviewer_ID)
ON DELETE SET NULL ON UPDATE CASCADE,

FOREIGN KEY (Mov_Id) REFERENCES MOVIE(Movie_ID)
ON DELETE SET DEFAULT ON UPDATE CASCADE
)

【讨论】:

“我找不到这个错误”是什么意思?你不能重现错误吗?或者你在问一个问题?或者是其他东西?这如何回答这个问题?你能详细说明一下吗?【参考方案29】:

我猜Clients.Case_Number 和/或Staff.Emp_IDClients_has_Staff.Clients_Case_NumberClients_has_Staff.Staff_Emp_ID 的数据类型不完全相同。

也许父表中的列是INT UNSIGNED

它们在两个表中的数据类型必须完全相同。

【讨论】:

您说得对,“这两个字段在两个表中应该是完全相同的数据类型。”谢谢。

以上是关于MySQL 错误 1215:无法添加外键约束的主要内容,如果未能解决你的问题,请参考以下文章

一般错误:1215 无法添加外键约束,Laravel 5 & MySQL

MYSQL Workbench - 错误:错误 1215:无法添加外键约束

MySQL 错误 [1215] [HY000] - 无法添加外键 [重复]

MySQL 1215无法添加外键约束 - Laravel 5

错误代码:1215。无法添加外键约束(外键)

错误代码:1215。无法添加外键约束(外键)