mysql创建带有外键的表,给出errno:150

tzcvj98z  于 2021-06-18  发布在  Mysql
关注(0)|答案(20)|浏览(499)

我试图在mysql中创建一个包含两个外键的表,这两个外键引用了另外两个表中的主键,但是我得到了一个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;

任何帮助都将不胜感激。

r8uurelv

r8uurelv1#

运行此脚本时,数据库的当前状态是什么?它完全是空的吗?当我从头开始创建数据库时,sql运行得很好,但是errno 150通常与删除和重新创建作为外键一部分的表有关。我觉得你不是在用一个100%全新的数据库工作。
如果您在“source”加载sql文件时出错,您应该能够在“source”命令之后立即从mysql提示符运行“show engine innodb status”命令,以查看更详细的错误信息。
您也可以查看手动输入:
如果重新创建已删除的表,则该表的定义必须符合引用它的外键约束。它必须具有正确的列名和类型,并且必须在引用的键上具有索引,如前面所述。如果不满足这些条件,mysql将返回错误号1005,并在错误消息中引用错误150。如果mysql在create table语句中报告错误号1005,并且错误消息指向错误150,则表创建失败,因为外键约束的格式不正确。
-MySQL5.1参考手册。

3okqufwl

3okqufwl2#

适用于mac os的mysql workbench 6.3。
问题:当尝试在db图上进行正向工程时,表x上的错误号为150,21个中有20个成功,1个失败。如果删除了表x上的fks,则错误将移到以前没有失败的其他表中。
把所有的表引擎都改成了myisam,效果很好。

inn6fuwd

inn6fuwd3#

当然不是这样,但我发现这个错误很常见,也不明显。目标 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));
4c8rllxm

4c8rllxm4#

当外键约束基于 varchar 键入,然后除了 marv-el 目标列必须具有唯一约束。

dphi5xsq

dphi5xsq5#

对于使用相同问题查看此线程的用户:
出现这样的错误有很多原因。有关mysql中外键错误的原因和解决方案的完整列表(包括这里讨论的),请查看以下链接:
mysql外键错误和errno 150

pepwfjgg

pepwfjgg6#

我找到了另一个失败的原因。。。区分大小写的表名。
对于此表定义

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上失败,这一事实花了我几个小时才弄清楚。希望这能帮助别人。

pexxcrt2

pexxcrt27#

确保尝试与约束链接的两个字段的属性完全相同。
通常,id列上的“unsigned”属性会让您感到困惑。

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

9udxz4iz8#

我也有同样的问题 ALTER TABLE ADD FOREIGN KEY .
一个小时后,我发现必须满足这些条件才能得到错误150:
父表必须存在,然后才能定义引用它的外键。必须按正确的顺序定义表:先定义父表,然后定义子表。如果两个表相互引用,则必须创建一个不带fk约束的表,然后创建第二个表,然后将fk约束添加到第一个带fk约束的表 ALTER TABLE .
这两个表都必须支持外键约束,即。 ENGINE=InnoDB . 其他存储引擎会自动忽略外键定义,因此不会返回错误或警告,但不会保存fk约束。
父表中引用的列必须是键的最左边的列。如果父级中的键是 PRIMARY KEY 或者 UNIQUE KEY .
fk定义必须以与pk定义相同的顺序引用pk列。例如,如果fk REFERENCES Parent(a,b,c) 则不能按顺序在列上定义父级的pk (a,c,b) .
父表中的pk列必须与子表中的fk列具有相同的数据类型。例如,如果父表中的pk列 UNSIGNED ,一定要定义 UNSIGNED 对于子表字段中的相应列。
例外:字符串的长度可能不同。例如, VARCHAR(10) can参考 VARCHAR(20) 反之亦然。
任何字符串类型的fk列必须与相应的pk列具有相同的字符集和排序规则。
如果子表中已有数据,则fk列中的每个值都必须与父表pk列中的值匹配。使用如下查询检查此问题:

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

这必须返回零(0)个不匹配的值。显然,这个查询是一个通用的例子;必须替换表名和列名。
父表和子表都不能是 TEMPORARY table。
父表和子表都不能是 PARTITIONED table。
如果你用 ON DELETE SET NULL 选项,则fk列必须可为空。
如果为外键声明约束名称,则约束名称在整个架构中必须是唯一的,而不仅仅是在定义约束的表中。两个表可能没有自己的同名约束。
如果其他表中有任何其他fk指向您试图为其创建新fk的同一字段,并且它们的格式不正确(即不同的排序规则),则需要首先使它们保持一致。这可能是过去变化的结果 SET FOREIGN_KEY_CHECKS = 0; 错误地定义了不一致的关系。有关如何识别这些问题fk的说明,请参见下面@andrewdotn的答案。
希望这有帮助。

n6lpvg4x

n6lpvg4x9#

正如@andrewdotn所指出的,最好的方法是查看详细的错误( SHOW ENGINE INNODB STATUS; )而不仅仅是一个错误代码。
其中一个原因可能是已经存在同名的索引,该索引可能位于另一个表中。作为实践,我建议在索引名之前加上表名前缀,以避免此类冲突。e、 g.代替 idx_userId 使用 idx_userActionMapping_userId .

muk1a3rh

muk1a3rh10#

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

hujrc8aj

hujrc8aj11#

对于其他通过google找到这个so条目的人:确保你没有试图对定义为“not null”的外键(to be)列执行set null操作。这导致了极大的挫败感,直到我记得检查引擎innodb status。

pxyaymoc

pxyaymoc12#

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

u5i3ibmn

u5i3ibmn13#

(旁注太大,无法发表评论)
不需要一个 AUTO_INCREMENT Map表中的id;把它扔掉。
更改 PRIMARY KEY(role_id, role_group_id) (按任意顺序)。这将使访问更快。
因为您可能想要Map两个方向,所以还需要添加一个 INDEX 以相反的顺序排列这两列(没有必要这么做 UNIQUE .)
更多提示:http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta

whhtz7ly

whhtz7ly14#

有用的提示,使用 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)                                                                                                                                                                           |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+

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

gdrx4gfi

gdrx4gfi15#

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

相关问题