MySQL外键错误1005 errno 150:将主键作为外键。

40
我正在使用MySQL Workbench制作一个小型数据库。我有一个名为“Immobili”的主表,它有一个由四个列(Comune、Via、Civico、Immobile)组成的主键。
此外,我还有三个其他表,它们具有相同的主键(Comune、Via、Civico、Immobile),但这些字段也与Immobilii表相关联。
第一个问题:我可以创建一个既是主键又是外键的关键字吗?
第二个问题:当我尝试导出更改时,它显示:
Executing SQL script in server

# ERROR: Error 1005: Can't create table 'dbimmobili.condoni' (errno: 150)

CREATE  TABLE IF NOT EXISTS `dbimmobili`.`Condoni` (

  `ComuneImmobile` VARCHAR(50) NOT NULL ,
  `ViaImmobile` VARCHAR(50) NOT NULL ,
  `CivicoImmobile` VARCHAR(5) NOT NULL ,
  `InternoImmobile` VARCHAR(3) NOT NULL ,
  `ProtocolloNumero` VARCHAR(15) NULL ,
  `DataRichiestaSanatoria` DATE NULL ,
  `DataSanatoria` DATE NULL ,
  `SullePartiEsclusive` TINYINT(1) NULL ,
  `SullePartiComuni` TINYINT(1) NULL ,
  `OblazioneInEuro` DOUBLE NULL ,
  `TecnicoOblazione` VARCHAR(45) NULL ,
  `TelefonoTecnico` VARCHAR(15) NULL ,
  INDEX `ComuneImmobile` (`ComuneImmobile` ASC) ,
  INDEX `ViaImmobile` (`ViaImmobile` ASC) ,
  INDEX `CivicoImmobile` (`CivicoImmobile` ASC) ,
  INDEX `InternoImmobile` (`InternoImmobile` ASC) ,

  PRIMARY KEY (`ComuneImmobile`, `ViaImmobile`, `CivicoImmobile`, `InternoImmobile`) ,

  CONSTRAINT `ComuneImmobile`
    FOREIGN KEY (`ComuneImmobile` )
    REFERENCES `dbimmobili`.`Immobile` (`ComuneImmobile` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,

  CONSTRAINT `ViaImmobile`
    FOREIGN KEY (`ViaImmobile` )
    REFERENCES `dbimmobili`.`Immobile` (`ViaImmobile` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,

  CONSTRAINT `CivicoImmobile`
    FOREIGN KEY (`CivicoImmobile` )
    REFERENCES `dbimmobili`.`Immobile` (`CivicoImmobile` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,

  CONSTRAINT `InternoImmobile`
    FOREIGN KEY (`InternoImmobile` )
    REFERENCES `dbimmobili`.`Immobile` (`InternoImmobile` )
    ON DELETE CASCADE
    ON UPDATE CASCADE
) ENGINE = InnoDB

显示引擎状态:

dbimmobili/valutazionimercato表的外键约束错误:

在被引用表中找不到一个索引,该索引中被引用的列出现在第一列,或者表和被引用表中的列类型不匹配。请注意,在使用InnoDB-4.1.12及以上版本创建的表中,ENUM和SET的内部存储类型已更改,旧表中的这些列不能被新表中的这些列引用。

我错在哪里了?

17个回答

52
创建外键约束时,MySQL要求引用表和被引用表都有可用的索引。如果引用表上没有索引,则会自动创建一个;但是,被引用表上的索引需要手动创建(来源)。您的似乎缺失了这个索引。
测试案例:
CREATE TABLE tbl_a (
    id int PRIMARY KEY,
    some_other_id int,
    value int
) ENGINE=INNODB;
Query OK, 0 rows affected (0.10 sec)

CREATE TABLE tbl_b (
    id int PRIMARY KEY,
    a_id int,
    FOREIGN KEY (a_id) REFERENCES tbl_a (some_other_id)
) ENGINE=INNODB;
ERROR 1005 (HY000): Can't create table 'e.tbl_b' (errno: 150)

但是如果我们在some_other_id上添加索引:

CREATE INDEX ix_some_id ON tbl_a (some_other_id);
Query OK, 0 rows affected (0.11 sec)
Records: 0  Duplicates: 0  Warnings: 0

CREATE TABLE tbl_b (
    id int PRIMARY KEY,
    a_id int,
    FOREIGN KEY (a_id) REFERENCES tbl_a (some_other_id)
) ENGINE=INNODB;
Query OK, 0 rows affected (0.06 sec)

在大多数情况下,这通常不是问题,因为所引用的字段通常是所引用表的主键,而主键会自动建立索引。


4
记住创建索引时的顺序,有时需要进行修正。 - CSchulz
我发现的一个问题是,如果在引用表中不给出字段名,则会导致错误。例如 FOREIGN KEY (a_id) REFERENCES tbl_a; 即使两个表中都有相同名称的字段。 - Natwar Singh
为了完成CShulz的评论,你必须注意多字段索引的索引。你必须检查引用表和被引用表之间的索引定义是否按相同的顺序定义。如果tab_a(引用表)具有a_id和b_id,则使用tab_b(被引用表)与aa_id和bb_id进行约束...使用约束绑定:a_id-aa_id和b_id-bb_id ...因此,如果使用的索引定义为tab_a_idx(a_id,b_id),请确保tab_b idx是(aa_id,bb_id),而不是(bb_id,aa_id)。 - Emmanuel Devaux
3
我刚遇到了和你一样的错误。问题最终是由于我引用的外键数据类型为“INT unsigned”。我不确定这是什么意思,但将其更改为“INT”就可以解决了。 - connorbode
遇到了同样的问题。这是由于外键名称重复引起的。 - IROEGBU
如果你的问题是有符号和无符号的区别,那么你没有将其与引用列的有符号/无符号设置匹配。这些列必须按数据类型和无符号设置匹配。 - Jroonk

32

请仔细检查外键的类型是否与此表字段的类型完全相同。例如,两者都应该是Integer(10)或Varchar(8),即使是字符数也应该相同。


是的,如果一个表的键是tinyint类型,而另一个表的键是int类型,即使它们的长度相同,也可能会失败。 - Robin Manoli
5
有符号/无符号整数也很重要!感谢你的回答,让我意识到了这一点。 - enrey
我有一个整数字段引用了一个大整数字段。我将它们都改成了相同的类型,然后成功了。这个答案在底部,我希望早点看到它。 - Ryan
2
即使是CAN_BE_NULL、UNSIGNED等标志,在两个字段之间的任何细微差别都可能导致这种错误。无论如何,感谢danp的帮助,这很有用。 - Pandaiolo
谢谢,这解决了我的问题。在被引用的表中,我有一个 customer_id int(20),而在引用的表中,我有:foreign key(_customer_id) references customer(customer_id),其中 _customer_id 被定义为 _customer_id int(10) - kholofelo Maloma
非常感谢,是整数的长度导致了那个错误。 - Dev_meno

16

我知道这篇文章是旧的,但它在谷歌上排名很高,所以我会添加我解决自己问题的方法。如果你有不同类型的表(例如MyISAM和InnoDB),你也会遇到这个错误。在这种情况下,InnoDB是默认的表类型,但一个表需要全文搜索,因此它被迁移到了MyISAM。在这种情况下,你不能创建一个引用MyISAM表的外键的InnoDB表。


9

我曾遇到过这个错误,并在我的情况下找到了错误的原因。我仍在回答这个旧帖子,因为它在谷歌排名比较靠前。

我想要链接的两列变量都是整数,但其中一个整数选中了“unsigned”。简单地取消选中即可修复我的错误。


9
如果您的键是CHAR / VARCHAR或类似类型,另一个可能的问题是不同的排序规则。请检查字符集是否相同。

这就是我的原因。我本来想把默认的latin1_swedish_ci改成utf8_unicode_ci,但误点了utf8mb4_unicode_ci - Leo

5

我曾经遇到过相同的错误。后来发现问题是我在主表中创建了BIGINT UNSIGNED类型的主键,但在第二个表中将其声明为仅为BIGINT类型的外键。

当我在第二个表中将外键声明为BIGINT UNSIGNED时,一切都起作用了,甚至不需要创建任何索引。

因此,这是主键和外键之间数据类型不匹配导致的错误:)


请注意,即使数据类型相同,表格之间的不同排序规则也可能导致此问题。 - akmad

4

我之前也遇到过同样的问题,但是我的解决方法完全不同。在数据库的其他位置上,我有一个同名的外键。这就导致了1005错误。

将我的外键重命名为更符合当前情况的名称后,问题得以解决。


3
  1. 确保两个表使用相同的引擎类型。
  2. 确保您要索引的字段具有相同的类型和长度。

3
在我的案例中,错误是由于“引用”表是“MyISAM”而“引用”表是“InnoDB”造成的。
将表引擎从“MyISAM”转换为“InnoDB”对我解决了问题。
ALTER TABLE table_name ENGINE=InnoDB;

我曾经遇到过同样的错误,奇怪的是MySql没有给出任何提示方向的错误信息。我建议从查询开始,将使用的表设置为相同的引擎(InnoDB)、字符集(utf8)和校对规则(utf8_general_ci)。始终检查创建查询是否对所有列名使用相同的CamelCase(小写)。检查您的主键、键和约束条件。 - Harm

1

在创建表时,请注意字符集COLLATE参数。 就FOREIGN KEY问题而言,类似于这样的东西:

CREATE TABLE yourTableName (
....
....
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

在我的情况下,我无法创建带有外键引用的表。首先,我收到了错误代码1005,这几乎什么也没说。然后我添加了COLLATE,最后出现了关于CHARSET的错误消息。
Error Code: 1253. COLLATION 'utf8_unicode_ci' is not valid for CHARACTER SET 'latin1'

在进行了那个更正之后,我的问题得到了解决。

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