MySQL创建带有外键给errno的表:150


98

我正在尝试使用两个外键在MySQL中创建一个表,这些外键引用了其他2个表中的主键,但出现了errno:150错误,它不会创建该表。

这是所有3个表的SQL:

CREATE TABLE role_groups (
  `role_group_id` int(11) NOT NULL `AUTO_INCREMENT`,
  `name` varchar(20),
  `description` varchar(200),
  PRIMARY KEY (`role_group_id`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `roles` (
  `role_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50),
  `description` varchar(200),
  PRIMARY KEY (`role_id`)
) ENGINE=InnoDB;

create table role_map (
  `role_map_id` int not null `auto_increment`,
  `role_id` int not null,
  `role_group_id` int not null,
  primary key(`role_map_id`),
  foreign key(`role_id`) references roles(`role_id`),
  foreign key(`role_group_id`) references role_groups(`role_group_id`)
) engine=InnoDB;

任何帮助将不胜感激。


1
您能否发布错误输出并告诉我们(三个命令中的)哪个命令导致了错误?
dave

4
周围的回响是auto_increment什么?那是无效的。Auto_increment是关键字,而不是标识符。
Bill Karwin 09年

Answers:


238

我也有同样的问题ALTER TABLE ADD FOREIGN KEY

一个小时后,我发现必须满足以下条件才能不出现错误150:

  1. 父表必须存在,然后才能定义外键以引用它。您必须以正确的顺序定义表:首先是父表,然后是子表。如果两个表相互引用,则必须创建一个没有FK约束的表,然后创建第二个表,然后使用将该FK约束添加到第一个表ALTER TABLE

  2. 这两个表都必须支持外键约束,即ENGINE=InnoDB。其他存储引擎静默忽略外键定义,因此它们不返回任何错误或警告,但不会保存FK约束。

  3. 父表中被引用的列必须是键的最左列。如果“父项”中的键为PRIMARY KEY或,则为最佳UNIQUE KEY

  4. FK定义必须以与PK定义相同的顺序引用PK列。例如,如果为FK,REFERENCES Parent(a,b,c)则不得在order列上定义父级的PK (a,c,b)

  5. 父表中的PK列必须与子表中的FK列具有相同的数据类型。例如,如果父表中的PK列为UNSIGNED,请确保UNSIGNED在子表字段中为相应的列定义。

    例外:字符串的长度可能不同。例如,VARCHAR(10)可以引用VARCHAR(20),反之亦然。

  6. 任何字符串类型的FK列都必须具有与相应PK列相同的字符集和排序规则。

  7. 如果子表中已经有数据,则FK列中的每个值都必须与父表PK列中的值匹配。使用以下查询来检查此内容:

    SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK 
    WHERE Parent.PK IS NULL;

    这必须返回零(0)个不匹配的值。显然,该查询是一个通用示例。您必须替换表名和列名。

  8. 父表和子表都不能是TEMPORARY表。

  9. 父表和子表都不能是PARTITIONED表。

  10. 如果使用ON DELETE SET NULL选项声明FK ,则FK列必须为空。

  11. 如果为外键声明约束名称,则约束名称在整个架构中必须唯一,而不仅在定义该约束的表中是唯一的。两个表可能没有相同名称的约束。

  12. 如果其他表中的其他FK指向您要为其创建新FK的相同字段,并且它们的格式不正确(即不同的排序规则),则需要首先使其一致。这可能是由于过去的更改而导致的,这种更改SET FOREIGN_KEY_CHECKS = 0;是由于错误定义的不一致关系而使用的。有关如何识别这些问题FK的说明,请参见下面的@andrewdotn的答案。

希望这可以帮助。


4
还有一件值得补充的事情:如果父表的PK超过一个字段,则FK中的字段顺序必须与PK中的顺序相同
Kip 2012年

26
这包括喜欢的东西int(11) unsigned NOT NULLVS int(11) NOT NULL
Glen Solsberry

4
ALTER TABLE table_name ENGINE = InnoDB;
TolMera

12
如果表定义为ENGINE = MyISAM,则它不会生成errno 150,因为它会忽略外键声明。这就像说避免汽车发动机故障的最佳方法是驾驶船。:-)
Bill Karwin

2
另外,如果您的约束ON DELETE规则是SET NULL确保外键实际上可以为NULL!我花了30分钟一遍又一遍地阅读此答案,确保我的表符合条件,但仍然出现错误150。然后我注意到我的FK是一个NOT NULL字段,这意味着该规则无法应用。
马丁·乔纳

62

MySQL的通用“ errno 150”消息“ 意味着未正确形成外键约束。” 您可能已经知道如果您正在阅读此页面,则通用的“ errno:150”错误消息确实没有帮助。然而:

您可以通过运行然后在输出中查找来获取实际的错误消息。SHOW ENGINE INNODB STATUS;LATEST FOREIGN KEY ERROR

例如,此尝试创建外键约束:

CREATE TABLE t1
(id INTEGER);

CREATE TABLE t2
(t1_id INTEGER,
 CONSTRAINT FOREIGN KEY (t1_id) REFERENCES t1 (id));

失败并显示错误Can't create table 'test.t2' (errno: 150)。除了这是外键问题之外,这没有告诉任何人其他有用的信息。但是运行SHOW ENGINE INNODB STATUS;,它会说:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
130811 23:36:38 Error in foreign key constraint of table test/t2:
FOREIGN KEY (t1_id) REFERENCES t1 (id)):
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.

它说问题在于它找不到索引。SHOW INDEX FROM t1显示table根本没有任何索引t1。通过在上定义主键来解决此问题t1,外键约束将成功创建。


4
SHOW ENGINE INNODB STATUS帮助我立即发现了将近一个小时试图诊断的问题。谢谢。
jatrim 2014年

在我的情况下,这表明FK指向我试图指向的同一字段的完全不同的表不一致,因此不会保存新表...假设这是SET FOREIGN_KEY_CHECKS = 0;在导入/更改中使用的,格式错误在一个或另一个时间。很大的帮助,谢谢。
oucil

25

确保您尝试与约束链接的两个字段的属性完全相同。

通常,ID列上的'unsigned'属性会吸引您。

ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;

以我的经验,值得在主表上使用MySQL的SHOW CREATE TABLE来检查针对主索引列设置的标志,然后将其复制到外键列。可能有些东西不明显,例如“ unsigned”。
Ambulare 2014年

10

运行此脚本时数据库的当前状态是什么?它是完全空的吗?从头开始创建数据库时,SQL对我来说运行良好,但是errno 150通常与删除和重新创建作为外键一部分的表有关。我感觉到您没有使用100%的新数据库。

如果在对SQL文件进行“源”化时出错,则应该能够在“源”命令后立即从MySQL提示符下运行命令“ SHOW ENGINE INNODB STATUS”,以查看更多详细的错误信息。

您可能还想查看手动输入:

如果重新创建已删除的表,则该表必须具有符合引用该表的外键约束的定义。如前所述,它必须具有正确的列名和类型,并且必须在引用的键上具有索引。如果不满足这些条件,MySQL将返回错误号1005,并在错误消息中引用错误150。如果MySQL从CREATE TABLE语句报告错误号1005,并且错误消息引用错误150,则表创建失败,因为未正确形成外键约束。

MySQL 5.1参考手册


5

对于使用相同问题查看此线程的人:

出现此类错误的原因很多。有关MySQL中外键错误的原因和解决方案的完整列表(包括此处讨论的内容),请查看以下链接:

MySQL外键错误和Errno 150


4

对于其他通过Google查找此SO条目的用户:请确保您不尝试对定义为“ NOT NULL”的外键列(将要使用)执行SET NULL操作。这引起了极大的挫败感,直到我记得做一个检查发动机的INNODB状态。


3

绝对不是这样,但我发现此错误非常普遍且不明显。a的目标FOREIGN KEY可能不是PRIMARY KEY。对我有用的答案是:

必须始终将FOREIGN KEY指向其他表的PRIMARY KEY true字段。

CREATE TABLE users(
   id INT AUTO_INCREMENT PRIMARY KEY,
   username VARCHAR(40));

CREATE TABLE userroles(
   id INT AUTO_INCREMENT PRIMARY KEY,
   user_id INT NOT NULL,
   FOREIGN KEY(user_id) REFERENCES users(id));

3

正如@andrewdotn指出的,最好的方法是查看详细的错误(SHOW ENGINE INNODB STATUS;)而不仅仅是错误代码。

原因之一可能是已经存在同名索引,可能在另一个表中。作为一种做法,我建议在索引名称之前添加表名称,以免发生这种冲突。例如代替idx_userId使用idx_userActionMapping_userId


3

请首先确保

  1. 您正在使用InnoDB表。
  2. FOREIGN KEY的字段与源字段具有相同的类型和长度(!)。

我遇到了同样的麻烦,并且已经解决了。我对一个字段使用了无符号INT,而对其他字段则使用了整数。


2

有用的提示,请SHOW WARNINGS;在尝试CREATE查询后使用,您将收到错误以及更详细的警告:

    ---------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                 |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+
| Warning |  150 | Create table 'fakeDatabase/exampleTable' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.
|
| Error   | 1005 | Can't create table 'exampleTable' (errno:150)                                                                                                                                                                           |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+

因此,在这种情况下,是时候重新创建我的表了!


1

当您尝试将文件来源到现有数据库时,通常会发生这种情况。首先删除所有表(或数据库本身)。然后在源文件SET foreign_key_checks = 0;的开头和SET foreign_key_checks = 1;结尾加上。


1

我发现失败的另一个原因...区分大小写的表名。

对于此表定义

CREATE TABLE user (
  userId int PRIMARY KEY AUTO_INCREMENT,
  username varchar(30) NOT NULL
) ENGINE=InnoDB;

该表定义有效

CREATE TABLE product (
  id int PRIMARY KEY AUTO_INCREMENT,
  userId int,
  FOREIGN KEY fkProductUser1(userId) REFERENCES **u**ser(userId)
) ENGINE=InnoDB;

而这一失败

CREATE TABLE product (
  id int PRIMARY KEY AUTO_INCREMENT,
  userId int,
  FOREIGN KEY fkProductUser1(userId) REFERENCES User(userId)
) ENGINE=InnoDB;

它在Windows上可以运行,而在Unix上却无法运行,这一事实使我花了几个小时才弄清楚。希望对别人有帮助。


1

适用于Mac OS的MySQL Workbench 6.3。

问题:尝试对数据库图进行正向工程时,表X上的错误号150,在21中成功20,失败1。如果删除了表X上的FK,该错误将移至之前没有发生过故障的其他表上。

将所有表引擎更改为myISAM,它工作正常。

在此处输入图片说明


0

同样值得检查的是,您不是意外操作了错误的数据库。如果外部表不存在,将发生此错误。为什么MySQL必须如此神秘?


0

确保外键在父级中未列为唯一。我遇到了同样的问题,并通过将其划分为非唯一的问题来解决了。


0

在我的情况下,这是由于作为外键字段的字段名称太长,即。foreign key (some_other_table_with_long_name_id)。尝试短一点。在这种情况下,错误消息会产生误导。

同样,正如@Jon前面提到的-字段定义必须相同(注意unsigned子类型)。




0

在创建表之前执行以下行:SET FOREIGN_KEY_CHECKS = 0;

FOREIGN_KEY_CHECKS选项指定是否检查InnoDB表的外键约束。

-指定检查外键约束(这是默认设置)

SET FOREIGN_KEY_CHECKS = 1;

 

-不要检查外键约束

SET FOREIGN_KEY_CHECKS = 0;

使用时间:当您需要重新创建表并以任何父子顺序加载数据时,临时禁用引用约束(将FOREIGN_KEY_CHECKS设置为0)非常有用


-1

我遇到了同样的问题,但是我检查发现我没有父表。因此,我只在子迁移之前编辑父迁移。去做就对了。


1
这本来应该是评论,而不是答案
Hannad Rehman
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.