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


335

我正在尝试将新架构向前工程到我的数据库服务器上,但是我不知道为什么会收到此错误。我试图在这里搜索答案,但是我发现的所有内容都说是将db引擎设置为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

6
请发布父表的架构:ClientsStaff
艾克·沃克


1
@Denis可能不是重复的,因为OP表示他们已经验证了父表中的列是PK。
艾克·沃克

我已根据要求为Clients和Staff表添加了SQL语句。
罗伯特·B

Answers:


592

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

也许父表中的列是INT UNSIGNED

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


10
谢谢。原来是问题所在。Staff.Emp_ID是SMALLINT,而引用列是INT。有时是些小事……
Robert B

Tks。在我的情况下,我不小心单击了子表中外键上的“ ZeroFill”,这意味着它与父表的列不完全匹配。
wwkudu 2014年

12
字符集也可能不同。我遇到了一个问题,其中一列具有utf8字符集,而另一列具有latin1。可以使用ALTER TABLE TableCHARACTER SET = utf8 轻松修复;和ALTER TABLE DeviceCHANGE COLUMN ID IDCHAR(36)CHARACTER SET'utf8'NOT NULL;
www.jensolsson.se 2015年

3
@ www.jensolsson.se是正确的,如果PK包含一个或多个字符串列,则它们必须使用相同的字符集排序规则。在此特定情况下,PK是INT,因此表和/或列的字符集无关。
Ike Walker

2
整理是我的问题,latin1 vs utf8(检查表和列)。
ben_979 '16

244

您可能会收到外键约束错误的原因:

  1. 您没有将InnoDB用作所有表的引擎。
  2. 您正在尝试引用目标表上不存在的键。确保它是另一个表上的(可以是主键或唯一键)
  3. 列的类型不相同(例外情况是引用表上的列可以为空)。
  4. 如果PK / FK是varchar,请确保两者的排序规则相同。

更新:

  1. 原因之一也可能是您要使用的列ON DELETE SET NULL未定义为空。因此,请确保将该列设置为默认null。

检查这些。


14
我要补充一点,如果FK在字符列上,我认为它们必须具有相同的字符集和排序规则。(或者可能是1字节和2字节字符集不兼容。)
Graham Charles

5
我的理由是您指出了第一个“用于两个表的不同数据库引擎,即InnoDB和MyISAM”
Randika Vishman 2015年

7
我有另一个原因=)```ON DELETE CASCADE ON UPDATE SET NULL:```尽管一些列被定义为NOT NULL,但是您已经定义了SET NULL条件。因此,我只修复FK定义。
alexglue

1
同样可能的失败是目标字段上没有索引
Paul T. Rawkeen

1
好的,第四点是我的问题。有点讨厌-但是我非常高兴mysql确实为此崩溃了
塞巴(Sebas)2013年

85

对于其他错误,相同的错误可能并非总是由于列类型不匹配而引起,您可以通过发出命令来查找有关mysql foriegn键错误的更多信息。

SHOW ENGINE INNODB STATUS;

您可能会在打印的消息顶部附近发现错误,例如

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


13
我认为这是最好的答案,因为它有助于诊断!谢谢。
alexglue 2015年

那应该如何工作?连续执行两个查询?
C4d

@ C4u,是的,我们应该先显示SHOW ENGINE INNODB STATUS,然后再执行其他查询,以连续执行两个查询
sureshd

在PHPMyAdmin上执行此操作无效。在命令提示符下执行此操作。
ruwan800

13

错误1215是令人讨厌的错误。爆炸药的答案涵盖了基础知识。您要确保从那里开始。但是,还有更多,更微妙的情况需要注意:

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

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

不会飞行,因为PRIMARY KEY(例如id)不能为NULL

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


1
如果您尝试删除不存在的外键,也会收到此错误:)
Explosion Pill 2014年

2
另外,从文档中:MySQL需要在外键和引用键上建立索引,以便外键检查可以快速进行,而无需进行表扫描。在引用表中,必须有一个索引,其中外键列以相同的顺序列为第一列。如果这样的索引不存在,则会在引用表上自动创建。如果您创建另一个可用于强制执行外键约束的索引,则以后可能会静默删除该索引。如果给定,则使用index_name(如前所述)。
Jonathan M

1
这就是我来这里的原因:我试图ON DELETE SET NULL在想要成为的列上创建外键NOT NULL。假设您也不能吃蛋糕。
马丁·亨宁斯

8

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

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

这是发生在我身上。


这就是我的问题-MySQL错误根本没有帮助!
拥抱

7

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


5

尝试添加fk时遇到相同的错误。在我的情况下,问题是由FK表的PK引起的,该PK被标记为未签名。


5

使用Laravel 4时,尤其是JeffreyWay的Laravel 4 Generators出现了“错误1215:无法添加外键约束”,我有一个陷阱。

在Laravel 4中,您可以使用JeffreyWay的Generators生成迁移文件,以一张一张地创建表,这意味着每个迁移文件都生成一张表。您必须意识到以下事实:每个迁移文件都是在文件名中带有时间戳的情况下生成的,该时间戳为文件指定了顺序。当您触发Artisan CLI命令“ php artisan migration”时,生成的顺序也是迁移操作的顺序。因此,如果文件要求引用将在后一个文件中生成但尚未生成的密钥的外键约束,则将引发错误1215。在这种情况下,您要做的就是调整迁移文件的生成顺序。以正确的顺序生成新文件,复制内容,然后删除混乱的旧文件。


3

我有同样的问题,我的解决方案:

之前:

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)

);

希望对您有所帮助;)


1
您在第一次创建时忘记了几个逗号
DLight

3

我有同样的问题。
我这样做解决了:

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

我尝试在架构生成器中导入表后发现了该解决方案。如果它适合您,请告诉我!

祝好运!

费利佩·特里西奥


3

我只是想为VARCHAR外键关系添加这种情况。我花了最后一周的时间试图在MySQL Workbench 8.0中弄清楚这一点,终于能够解决该错误。

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

长答案: 我的表中有一个ENUM数据类型。我将其更改为,VARCHAR并且可以从参考表中获取值,因此不必更改父表即可添加其他选项。这种外键关系似乎很简单,但是我却遇到了1215错误。arvind的回答和以下链接建议使用

SHOW ENGINE INNODB STATUS;

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

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

之后,我SET FOREIGN_KEY_CHECKS=0;按照Arvind Bharadwaj的建议以及此处的链接使用:

这给出了以下错误信息:

<BR> 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。这是一个更多讨论此排序规则的链接


2

我找不到此错误

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
)

2

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

例如,如果您要引用的列是UNSIGNED INT,而被引用的列是INT,则会出现此错误。


2

对于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

可能会像

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;

2

检查表兼容性。例如,如果一个表是MyISAM,而另一个表是,则InnoDB可能会出现此问题。


2

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

根据我的理解,关于数据完整性不是问题,但是MySQL似乎不支持此功能(在5.7中)。


1

当由于引用的表使用MyISAM引擎而发生此错误时,此答案提供了一种转换数据库的快速方法,因此所有Django模型表都使用InnoDB:https : //stackoverflow.com/a/15389961/2950621

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


1

噢,我知道了!它混合了许多已经发布的答案(innoDB,未签名等)。我在这里没有看到的一件事是:如果FK指向PK,请确保source列具有有意义的值。例如,如果PK是mediumint(8),请确保源列也包含mediumint(8)。这对我来说是问题的一部分。


1

对我来说,这是列类型。BigINT!= INT。

但是后来还是没用。

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


1

由于完全不同的原因,我遇到了此错误。我使用MySQL Workbench 6.3创建数据模型(了不起的工具)。我注意到,当外键约束定义中定义的列顺序不适合表列序列时,也会生成此错误。

我花了大约4个小时尝试其他所有步骤,但仍进行了检查。

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


你是什​​么意思?
Yazan Jaber

2
@YazanJaber我想他的意思是这样:InnoDB的允许外键引用列的任何索引列或组。但是,在引用表中,必须有一个索引,其中引用列以相同的顺序列为第一列。
罗布(Robsch)

1

当尝试使用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
jagad89 '19


0

也要注意使用反引号。我在脚本中有以下声明

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没有给出关于此错误的详细信息...


0

此错误的另一个来源是您有2个或多个具有相同外键名称的相同表名。使用建模和设计软件(例如Mysql Workbench)并随后从设计生成脚本的人有时会发生这种情况。


0

我知道我晚会很晚,但是我想把它放在这里以便列出。

除了上述所有关于确保字段定义相同且表类型也具有相同排序规则的建议之外,请确保不要犯尝试在未链接CHILD字段中数据的情况下尝试链接字段的菜鸟错误。已经在PARENT字段中。如果您尚未在CHILD字段中输入的数据尚未输入PARENT字段中,则将导致此错误。很遗憾该错误消息没有多大帮助。

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

祝好运。


0

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

因此,长话短说,如果出现此错误,则可能是正在创建的表的外键。


0

对我来说,导入由mysqldump创建的转储文件时会发生1215错误,该转储文件按字母顺序创建表,在我的情况下,这会导致外键引用文件中稍后创建的表。(指出该页面的建议:https : //www.percona.com/blog/2017/04/06/dealing-mysql-error-code-1215-cannot-add-foreign-key-constraint/

由于mysqldump按字母顺序对表进行排序,并且我不想更改表的名称,因此我按照JeremyWeir 在本页上的回答进行了说明,该说明指出将其放在set FOREIGN_KEY_CHECKS = 0;转储文件的顶部,并将其放在转储文件SET FOREIGN_KEY_CHECKS = 1;的底部。

该解决方案对我有用。


0

因此,我尝试了上述所有修复措施,但没有运气。我可能在表中缺少该错误-只是找不到原因,并且不断出现错误1215。因此我使用了此修复程序。

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

我在博客上发布了修复程序。


-1

即使我也有同样的问题。而且故障出在FK表PK中的“未签名”标记上


-6

我曾经有过同样的错误。我只是简单地重新启动了MySQL服务器并解决了问题。


这根本不能解决问题。
James111
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.