MySQL使用提供errno:150的外键创建表
我想在两个外键的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;
任何帮助将不胜感激。
我有与ALTER TABLE ADD FOREIGN KEY
相同的问题。
一个小时之后,我发现这些条件必须得到满足,才能得到错误150:
- 这两个表必须具有相同的引擎,引擎必须支持外键。 例如,
ENGINE=InnoDB
。 其他存储引擎默默地忽略外键定义,所以它们不会返回错误或警告,但FK约束不会被保存。 - 父表中引用的列必须是密钥的最左边的列。 最好如果钥匙是
PRIMARY KEY
或UNIQUE KEY
。 - FK定义必须以与PK定义相同的顺序引用PK列。 例如,如果FK
REFERENCES Parent(a,b,c)
则不能按顺序(a,c,b)
在列上定义父项的PK。 -
Parent表中的PK列必须与Child表中的FK列的数据类型相同。 例如,如果Parent表中的PK列是
UNSIGNED
,请务必为Child表字段中的相应列定义UNSIGNED
。例外:字符串的长度可能不同。 例如,
VARCHAR(10)
可以引用VARCHAR(20)
,反之亦然。 - 任何字符串类型的FK列必须与相应的PK列具有相同的字符集和归类。
-
如果Child表中已有数据,则FK列中的每个值都必须与父表PK列中的值相匹配。 用下面的查询来检查:
SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK WHERE Parent.PK IS NULL;
这必须返回零(0)不匹配的值。 显然,这个查询是一个通用的例子。 你必须替换你的表名和列名。
- 父表和子表都不能是
TEMPORARY
表。 - 父表和子表都不能是
PARTITIONED
表。
希望这可以帮助。
MySQL的通用“errno 150”消息意味着一个外键约束没有正确的形成 。“你可能已经知道,如果你正在阅读这个页面,通用的”errno:150“错误信息确实是无益的。 然而:
您可以通过运行SHOW ENGINE INNODB STATUS;
来获得实际的错误信息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
显示表t1
没有任何索引。 通过在t1
上定义一个主键来解决这个问题,并且外键约束将被成功创建。
确保您试图链接到约束的两个字段的属性完全相同。
通常,ID列上的“未签名”属性会将您吸引。
ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;
当你运行这个脚本时,数据库的当前状态是什么? 它完全是空的吗? 从头开始创建数据库时,您的SQL可以正常运行,但是errno 150通常需要删除和重新创建属于外键的表。 我觉得你没有100%的新鲜和新的数据库的工作。
如果您在SQL语句的源文件中出错时,应该能够在“source”命令之后立即运行“SHOW ENGINE INNODB STATUS”命令来查看更详细的错误信息。
你也可以查看手册条目:
如果您重新创建一个被删除的表,它必须有一个符合引用它的外键约束的定义。 它必须具有正确的列名和类型,并且必须在引用的键上有索引,如前所述。 如果不满足,MySQL将返回错误号1005,并在错误信息中引用错误150。 如果MySQL从CREATE TABLE语句报告了错误号1005,并且错误消息引用了错误150,则表的创建失败,因为外键约束未正确形成。
– MySQL 5.1参考手册
对于正在查看此线程的人有相同的问题:
得到这样的错误有很多原因。 有关MySQL的外键错误的原因和解决方案的完整列表(包括这里讨论的那些错误),请查看以下链接:
MySQL外键错误和Errno 150
对于通过Google发现此SO条目的其他人:确保您没有试图对定义为“NOT NULL”的外键(要)执行SET NULL操作。 这让我感到非常沮丧,直到我记得做一个CHECK ENGINE INNODB STATUS。
当然不是这样,但是我发现这个错误很常见而且不明显。 FOREIGN KEY
的目标可能不是PRIMARY KEY
。 对我有用的答案是:
一个FOREIGN KEY总是必须指向另一个表的PRIMARY KEY真实字段。
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));
正如@andrewdotn所指出的,最好的方法是查看详细的错误( SHOW ENGINE INNODB STATUS;
)而不是一个错误代码。
其中一个原因可能是一个索引已经存在同名,可能在另一个表中。 作为惯例,我建议在索引名称之前加上表名,以避免这种冲突。 例如,而不是idx_userId
使用idx_userActionMapping_userId
。
有用的提示,使用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) | +---------+------+-------------------------------------------------------------------------- -------------------------------------------------------------------------------------------- ---------------+
所以在这种情况下,重新创建我的表的时间!
请首先确认
- 你正在使用InnoDB表。
- FOREIGN KEY字段与源字段具有相同的类型和长度(!)。
我有同样的麻烦,我已经修好了。 我有一个字段的INT无符号,其他字段只是整数。
当您尝试将文件编入现有数据库时,通常会发生这种情况。 首先删除所有表(或数据库本身)。 然后使用SET foreign_key_checks = 0;
来源文件SET foreign_key_checks = 0;
在开始和SET foreign_key_checks = 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上失败的事实花了我几个小时才弄清楚。 希望能帮助别人。
适用于Mac OS的MySQL Workbench 6.3。
问题:试图在DB图上执行Forward Engineering时,表X上的errno 150,21个中的20个成功,1个失败。 如果表X上的FK被删除,那么错误将移到另一个没有失败的表上。
所有表引擎更改为myISAM,它工作得很好。
还值得检查一下,你是不是意外地在错误的数据库上运行。 如果外表不存在,则会发生此错误。 为什么MySQL必须如此神秘?
确保外键在父级中未被列为唯一。 我也遇到了同样的问题,我把它划分为不是唯一的。
就我而言,这是因为外地领域的名字太长, foreign key (some_other_table_with_long_name_id)
。 尝试一下。 错误信息在这种情况下有点误导。
此外,正如@Jon前面提到的 – 字段定义必须是相同的(小心unsigned
子类型)。
当关键约束基于varchar
类型时,除了由marv-el
提供的列表之外, 目标列必须具有唯一的约束。