在MySQL中添加外键失败,出现错误代码1005,编号为150。

14

我正在尝试向我的一个表格中添加一个新的外键,如下所示:

 ALTER TABLE `UserTransactions`.`ExpenseBackTransactions` 
   ADD CONSTRAINT `FK_EBTx_CustomAccountID`
   FOREIGN KEY (`CustomAccountID` )
   REFERENCES `UserTransactions`.`CustomAccounts` (`CustomAccountID`)
   ON DELETE NO ACTION
   ON UPDATE NO ACTION,
   ADD INDEX `FK_EBTx_CustomAccountID` (`CustomAccountID` ASC) ;

我一直得到以下错误:

Error Code: 1005
Can't create table './UserTransactions/#sql-187a_29.frm' (errno: 150)

我之前对这个和其他表格做了相当多的更改,但这是我第一次遇到这个问题。有任何想法是什么导致了这个问题吗?

更新:

我的 SHOW INNODB STATUS 错误信息:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
110525 15:56:36 Error in foreign key constraint of table UserTransactions/#sql-187a_2c:

  FOREIGN KEY (`CustomAccountID` )
  REFERENCES `UserTransactions`.`CustomAccounts` (`CustomAccountID` )
  ON DELETE NO ACTION
  ON UPDATE NO ACTION
, ADD INDEX `FK_EBTx_CustomAccountID` (`CustomAccountID` ASC):
Cannot resolve table name close to:
 (`CustomAccountID` )
  ON DELETE NO ACTION
  ON UPDATE NO ACTION
, ADD INDEX `FK_EBTx_CustomAccountID` (`CustomAccountID` ASC)

SHOW INNODB STATUS 显示了什么?这两列的数据类型(和长度)是否相同?数据库中是否已经有另一个使用该名称的键? - Konerak
FOREIGN KEY 只被 InnoDB 支持 http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html。检查是否导致了问题。 - Ibrahim Azhar Armar
@Ibrahim:MyISAM在不报错的情况下默默地忽略外键规范。 - Marc B
3个回答

28

这里有一个 不错的清单

以下是已知导致恼人的 errno 150 的原因列表:

  1. 两个关键字段的类型和/或大小不完全匹配。例如,如果一个是 INT(10),则关键字段也需要是 INT(10),而不是 INT(11) 或 TINYINT。您可以使用 SHOW CREATE TABLE 确认字段大小,因为 Query Browser 有时会将 INT(10) 和 INT(11) 都显示为 INTEGER。您还应该检查其中一个是否为 SIGNED 而另一个是否为 UNSIGNED。它们必须完全相同(有关 signed vs unsigned 更多信息请参阅此处)。
  2. 您尝试引用的关键字段之一没有索引和/或不是主键。如果关系中的某个字段不是主键,则必须为该字段创建索引。(感谢 Venkatesh、Erichero 和 Terminally Incoherent 提供此提示)
  3. 外键名称是已经存在的键的重复项。检查您的外键名称在数据库中是否唯一。只需在您的键名末尾添加几个随机字符以测试此情况。(感谢 Niels 提供此提示)
  4. 您的一个或两个表是 MyISAM 表。为了使用外键,两个表都必须是 InnoDB。(实际上,如果两个表都是 MyISAM,则不会收到错误消息,它只是不会创建键。)在 Query Browser 中,您可以指定表类型。
  5. 您已经指定了一个 ON DELETE SET NULL 级联,但相关的关键字段设置为 NOT NULL。您可以通过更改级联或将该字段设置为允许 NULL 值来解决此问题。(感谢 Sammy 和 J Jammin 提供此提示)
  6. 确保表级别和关键列的字段级别上的字符集(Charset)和排序规则(Collate)选项相同。(感谢FRR提供的提示)
  7. 在外键列上设置默认值(如default=0)(感谢Omar提供的提示)
  8. 关系中的某个字段是组合(复合)键的一部分,并且没有自己单独的索引。即使该字段作为组合键的一部分具有索引,您也必须为仅该键字段创建单独的索引,以便在约束中使用它。(感谢Alex提供的提示)
  9. 您的ALTER语句存在语法错误或者您在关系中拼写了一个字段名(感谢Christian和Mateo提供的提示)
  10. 外键名称超过了64个字符的最大长度。(感谢Nyleta提供的提示)

2
结果表格被意外地创建为MyISAM而不是InnoDB。这是一种非常有趣的ID-10-T错误暴露方式。 - thaBadDawg
如果没有那个清单,我可能会搜索几个小时...看起来另一个表是在MySQL安装尚不支持InnoDB时创建的。 - BurninLeo
  1. 表格或列存在于你尝试引用的外键中。这是一个简单的事情,有时像我这样的人会忘记。
- Ian

3
根据我的经验,errno: 150通常表示关键表中的FOREIGN KEY列和相关表中的数据类型不同。请确保CustomAccounts.CustomAccountIDExpenseBackTransactions.CustomAccountID的类型完全相同,包括如适用的UNSIGNED
如果这不能解决问题,请发帖留言SHOW CREATE TABLE ExpenseBackTransactions;SHOW CREATE TABLE CustomAccounts;

你的意思是 show create table,对吗?但除此之外,没错。很可能是两个表之间字段类型不匹配的问题。 - Marc B

0

进退两难。外键需要索引。MySQL不会按照查询顺序创建索引,因此在进行外键检查时索引可能不存在。因此,需要先创建索引,然后再使用两个单独的查询添加外键。


尝试过了,认为那就是错误所在,但在运行ADD INDEX命令后,仅使用ADD CONSTRAINT命令并没有起作用。 - thaBadDawg
这在早期的MySQL版本上是正确的,但在任何最近的5.x系列版本中已经不再是了。 - Marc B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接