我试图在MySQL中创建一个带有两个外键的表,它引用了另外两个表中的主键,但是我得到一个错误: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;
任何帮助将不胜感激 .
19 回答
我和
ALTER TABLE ADD FOREIGN KEY
有同样的问题 .一小时后,我发现必须满足这些条件才能得到错误150:
在定义引用它的外键之前,父表必须存在 . 您必须按正确的顺序定义表:首先是父表,然后是子表 . 如果两个表互相引用,则必须创建一个没有FK约束的表,然后创建第二个表,然后使用
ALTER TABLE
将FK约束添加到第一个表 .这两个表必须都支持外键约束,即
ENGINE=InnoDB
. 其他存储引擎默默地忽略外键定义,因此它们不返回错误或警告,但不保存FK约束 .Parent表中引用的列必须是键的最左侧列 . 如果父项中的键是
PRIMARY KEY
或UNIQUE KEY
,则为最佳 .FK定义必须以与PK定义相同的顺序引用PK列 . 例如,如果FK
REFERENCES Parent(a,b,c)
则不能在(a,c,b)
的列上定义父PK .Parent表中的PK列必须与Child表中的FK列具有相同的数据类型 . 例如,如果父表中的PK列为
UNSIGNED
,请确保为子表字段中的相应列定义UNSIGNED
.例外:字符串的长度可能不同 . 例如,
VARCHAR(10)
可以引用VARCHAR(20)
,反之亦然 .任何字符串类型的FK列必须与相应的PK列具有相同的字符集和排序规则 .
如果Child表中已存在数据,则FK列中的每个值都必须与父表PK列中的值匹配 . 使用如下查询检查:
这必须返回零(0)个不匹配的值 . 显然,这个查询是一个通用的例子;您必须替换您的表名和列名 .
Parent表和Child表都不能是
TEMPORARY
表 .Parent表和Child表都不能是
PARTITIONED
表 .如果使用
ON DELETE SET NULL
选项声明FK,则FK列必须可为空 .如果声明外键的约束名称,则约束名称在整个模式中必须是唯一的,而不仅仅是在定义约束的表中 . 两个表可能没有自己的具有相同名称的约束 .
希望这可以帮助 .
MySQL的通用“errno 150”消息“means that a foreign key constraint was not correctly formed . ”您可能已经知道如果您正在阅读此页面,通用的“errno:150”错误消息实际上是无益的 . 然而:
You can get the actual error message by running SHOW ENGINE INNODB STATUS; and then looking for LATEST FOREIGN KEY ERROR in the output.
例如,这种尝试创建外键约束:
失败并显示错误
Can't create table 'test.t2' (errno: 150)
. 除了它是一个外键问题之外,这并没有告诉任何人有用的东西 . 但运行SHOW ENGINE INNODB STATUS;
,它会说:它说问题是找不到索引 .
SHOW INDEX FROM t1
表示表t1
根本没有任何索引 . 修复,例如,在t1
上定义主键,将成功创建外键约束 .确保您尝试使用约束链接的两个字段的属性完全相同 .
通常,ID列上的“unsigned”属性会引起您的注意 .
运行此脚本时,数据库的当前状态是什么?它完全是空的吗?从头开始创建数据库时,您的SQL运行正常,但是errno 150通常与删除和重新创建属于外键的表有关 . 我感觉你没有使用100%全新的数据库 .
如果您在“源”处理SQL文件时出错,您应该能够在“source”命令之后立即从MySQL提示符运行命令“SHOW ENGINE INNODB STATUS”以查看更详细的错误信息 .
您可能还想查看手册条目:
对于正在查看具有相同问题的此线程的人:
得到这样的错误有很多原因 . 有关MySQL中外键错误的原因和解决方案的完整列表(包括此处讨论的那些),请查看此链接:
MySQL Foreign Key Errors and Errno 150
对于通过Google找到此SO条目的其他人:确保您没有尝试对定义为“NOT NULL”的外键(待定)列执行SET NULL操作 . 在我记得做CHECK ENGINE INNODB状态之前,这引起了极大的挫败感 .
当然不是这样,但我发现这个错误很常见而且不明显 .
FOREIGN KEY
的目标可能不是PRIMARY KEY
. 对我有用的答案是:A FOREIGN KEY always must be pointed to a PRIMARY KEY true field of other table.
正如@andrewdotn所指出的,最好的方法是查看详细错误(
SHOW ENGINE INNODB STATUS;
),而不仅仅是错误代码 .其中一个原因可能是索引已经存在,名称相同,可能在另一个表中 . 作为一种做法,我建议在索引名称前加上表名前缀,以避免此类冲突 . 例如而不是
idx_userId
使用idx_userActionMapping_userId
.有用的提示,在尝试
CREATE
查询后使用SHOW WARNINGS;
,您将收到错误以及更详细的警告:所以在这种情况下,有时间重新创建我的表!
请先确认一下
FOREIGN KEY的
我遇到了同样的麻烦,我已经修好了 . 我有一个字段的无符号INT和其他字段的整数 .
当您尝试将文件源文件导入现有数据库时,通常会发生这种情况 . 首先删除所有表(或DB本身) . 然后在源文件开头
SET foreign_key_checks = 0;
,最后SET foreign_key_checks = 1;
.我发现了这个失败的另一个原因......区分大小写的表名 .
对于此表定义
此表定义有效
而这一次失败了
它在Windows上工作并在Unix上失败的事实花了我几个小时来弄明白 . 希望能帮助别人 .
适用于Mac OS的MySQL Workbench 6.3 .
问题:当在DB图上尝试进行正向工程时,表X上的错误150,21个中的20个成功,1个失败 . 如果删除了表X上的FK,则错误将移至另一个之前未失败的表 .
将所有表引擎更改为myISAM,它工作得很好 .
另外值得检查的是,您不会意外地在错误的数据库上运行 . 如果外部表不存在,则会发生此错误 . 为什么MySQL必须如此神秘?
确保外键未在父项中列为唯一键 . 我有同样的问题,我通过将其划分为不唯一来解决它 .
在我的情况下,这是因为作为外键字段的字段名称太长,即 .
foreign key (some_other_table_with_long_name_id)
. 试试......更短 . 在这种情况下,错误消息有点误导 .另外,正如@Jon前面提到的那样 - 字段定义必须相同(注意
unsigned
子类型) .当foraign键约束基于
varchar
类型时,则除了list provided by marv-el之外 target column must have an unique constraint.(旁注对评论来说太大了)
映射表中不需要
AUTO_INCREMENT
id;摆脱它 .将
PRIMARY KEY
更改为(role_id, role_group_id)
(按任意顺序) . 这将使访问更快 .由于您可能希望映射两个方向,因此也要按相反顺序添加
INDEX
这两列 . (没有必要使它UNIQUE
. )更多提示:http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta
我遇到了同样的问题,但我检查发现我没有父表 . 所以我只是在子迁移前编辑父迁移 . 去做就对了 .