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

时间:2013-06-06 18:04:58

标签: mysql foreign-keys

我正在尝试将我的新架构转发到我的数据库服务器上,但我无法弄清楚为什么我收到此错误。我试图在这里搜索答案,但我发现的所有内容都说要么将数据库引擎设置为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

32 个答案:

答案 0 :(得分:521)

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

父表中的列可能是INT UNSIGNED

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

答案 1 :(得分:209)

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

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

    1. 其中一个原因可能是您用于ON DELETE SET NULL的列未定义为null。因此,请确保将列设置为default null。
    2. 检查这些。

答案 2 :(得分:76)

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

SHOW ENGINE INNODB STATUS;

您可能会在打印消息顶部附近找到错误,例如

  

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

答案 3 :(得分:12)

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

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

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

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

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

答案 4 :(得分:8)

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

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

发生在我身上。

答案 5 :(得分:7)

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

答案 6 :(得分:5)

使用Laravel 4时,我遇到了“错误1215:无法添加外键约束”的缺陷,特别是对于JeffreyWay的Laravel 4 Generators。

在Laravel 4中,您可以使用JeffreyWay的Generators生成迁移文件以逐个创建表,这意味着每个迁移文件生成一个表。 您必须知道每个迁移文件都是使用文件名中的时间戳生成的,这会为文件提供订单。当您触发Artisan CLI命令“php artisan migrate”时,生成顺序也是迁移操作的顺序。 因此,如果文件要求引用将在后一个文件中生成但尚未生成的密钥的外键约束,则会触发错误1215。 在这种情况下,您需要做的是调整迁移文件生成的顺序。按正确顺序生成新文件,复制内容,然后删除无序旧文件。

答案 7 :(得分:4)

我在尝试添加fk时遇到了同样的错误。在我的情况下,问题是由FK表的PK标记为无符号引起的。

答案 8 :(得分:3)

我遇到了同样的问题 我解决了这个问题:

我在中创建了以下行 primary key: (id int(11) unsigned NOT NULL AUTO_INCREMENT)

我尝试在架构构建器中导入表后找到了此解决方案。如果它适合您,请告诉我!

祝你好运!

FelipeTércio

答案 9 :(得分: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)

);

我希望它有所帮助;)

答案 10 :(得分: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
)

答案 11 :(得分:2)

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

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

答案 12 :(得分:2)

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

答案 13 :(得分:2)

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

e.g。如果您引用的列是UNSIGNED INT并且引用的列是INT,则会出现此错误。

答案 14 :(得分: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;

答案 15 :(得分:1)

我只是想为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,详细介绍了这种归类。

答案 16 :(得分:1)

对我而言,这是列类型。 BigINT!= INT。

然而它仍然没有奏效。

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

答案 17 :(得分:1)

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

我花了大约4个小时尝试其他所有事情,但是检查了一下。

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

答案 18 :(得分:1)

我知道了!这是很多已发布的答案(innoDB,unsigned等)的混合。我在这里没有看到的一件事是:如果您的FK指向PK,请确保源列具有合理的值。例如,如果PK是mediumint(8),请确保源列还包含mediumint(8)。这对我来说是问题的一部分。

答案 19 :(得分:1)

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

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

答案 20 :(得分:0)

此错误的另一个来源是您有两个或多个具有相同外键名称的相同表名。这有时会发生在使用建模和设计软件的人身上,例如Mysql Workbench,然后从设计中生成脚本。

答案 21 :(得分: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很遗憾没有关于此错误的详细信息...

答案 22 :(得分:0)

在使用laravel migration时尝试创建外键

就像这个例子:

用户表

    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

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

要解决此问题,应更改[colors table]

中的主键

$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');

答案 23 :(得分:0)

我知道我参加派对的时间非常晚,但我想把它放在这里,以便列出来。

除了确保字段具有相同定义的所有上述建议,以及表格类型也具有相同的排序规则之外,请确保您没有尝试链接字段中的数据的新手错误CHILD字段不在PARENT字段中。如果您在CHILD字段中的数据尚未输入PARENT字段,则会导致此错误。遗憾的是错误消息没有多大帮助。

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

祝你好运。

答案 24 :(得分:0)

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

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

答案 25 :(得分:0)

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

SET FOREIGN_KEY_CHECKS=0;

答案 26 :(得分:0)

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

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

该解决方案对我有用。

答案 27 :(得分:0)

@Explosion Pills answer above添加另一个原因:

  

7-使用多列键时,外键创建的顺序   必须与表格列顺序中的另一个相符。

答案 28 :(得分:0)

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

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

我在blog上发布了修复程序。

答案 29 :(得分:0)

我遇到了同样的问题,

所以我去了父表,我在创建语句时看到了这一行。

ENGINE=InnoDB DEFAULT CHARSET=utf8;

因此在创建它时向该代码行添加了一个子表。

答案 30 :(得分:-1)

即使我有同样的问题。错误在于FK表PK中的“无符号”标记

答案 31 :(得分:-6)

我曾经遇到过同样的错误。我只是简单地重新启动MySQL服务器并修复了问题。

相关问题