MySQL 使用外键创建表给出 errno: 150
我试图在 MySQL 中创建一个带有两个外键的表,这两个外键引用另外 2 个表中的主键,但是我收到了 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;
I am trying to create a table in MySQL with two foreign keys, which reference the primary keys in 2 other tables, but I am getting an errno: 150
error and it will not create the table.
Here is the SQL for all 3 tables:
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;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(20)
必须满足这些条件,才能避免在
ALTER TABLE ADD FOREIGN KEY
中出现错误 150:在定义外键来引用它之前,父表必须存在。您必须按正确的顺序定义表:首先是父表,然后是子表。如果两个表相互引用,则必须创建一个没有 FK 约束的表,然后创建第二个表,然后使用 ALTER TABLE 将 FK 约束添加到第一个表。
这两个表必须都支持外键约束,即
ENGINE=InnoDB
。其他存储引擎默默地忽略外键定义,因此它们不会返回错误或警告,但不会保存 FK 约束。父表中引用的列必须是键的最左边的列。如果父项中的键是
PRIMARY KEY
或UNIQUE KEY
,则最好。FK 定义必须以与 PK 定义相同的顺序引用 PK 列。例如,如果 FK
REFERENCES Parent(a,b,c)
,则不得按(a,c,b)
的顺序在列上定义 Parent 的 PK。< /p>父表中的 PK 列必须与子表中的 FK 列具有相同的数据类型。例如,如果父表中的 PK 列是
UNSIGNED
,请务必为子表字段中的相应列定义UNSIGNED
。例外:字符串的长度可能不同。例如,
VARCHAR(10)
可以引用VARCHAR(20)
,反之亦然。任何字符串类型的 FK 列必须与相应的 PK 列具有相同的字符集和排序规则。
如果子表中已有数据,则 FK 列中的每个值都必须与父表 PK 列中的值匹配。使用如下查询检查这一点:
这必须返回零 (0) 个不匹配的值。显然,这个查询是一个通用的例子;您必须替换表名和列名。
父表和子表都不能是
TEMPORARY
表。父表和子表都不能是 PARTITIONED 表。
如果使用
ON DELETE SET NULL
选项声明 FK,则 FK 列必须可为空。如果为外键声明约束名称,则该约束名称在整个架构中必须是唯一的,而不仅仅是在定义该约束的表中唯一。两个表不能有自己的同名约束。
如果其他表中有任何其他 FK 指向您尝试为其创建新 FK 的同一字段,并且它们格式错误(即不同的排序规则),则需要首先使它们保持一致。这可能是由于过去的更改造成的,其中
SET FOREIGN_KEY_CHECKS = 0;
被错误地定义为不一致的关系。有关如何识别这些问题 FK 的说明,请参阅下面 @andrewdotn 的回答。These conditions must be satisfied to not get error 150 re
ALTER TABLE ADD FOREIGN KEY
:The Parent table must exist before you define a foreign key to reference it. You must define the tables in the right order: Parent table first, then the Child table. If both tables references each other, you must create one table without FK constraints, then create the second table, then add the FK constraint to the first table with
ALTER TABLE
.The two tables must both support foreign key constraints, i.e.
ENGINE=InnoDB
. Other storage engines silently ignore foreign key definitions, so they return no error or warning, but the FK constraint is not saved.The referenced columns in the Parent table must be the left-most columns of a key. Best if the key in the Parent is
PRIMARY KEY
orUNIQUE KEY
.The FK definition must reference the PK column(s) in the same order as the PK definition. For example, if the FK
REFERENCES Parent(a,b,c)
then the Parent's PK must not be defined on columns in order(a,c,b)
.The PK column(s) in the Parent table must be the same data type as the FK column(s) in the Child table. For example, if a PK column in the Parent table is
UNSIGNED
, be sure to defineUNSIGNED
for the corresponding column in the Child table field.Exception: length of strings may be different. For example,
VARCHAR(10)
can referenceVARCHAR(20)
or vice versa.Any string-type FK column(s) must have the same character set and collation as the corresponding PK column(s).
If there is data already in the Child table, every value in the FK column(s) must match a value in the Parent table PK column(s). Check this with a query like:
This must return zero (0) unmatched values. Obviously, this query is an generic example; you must substitute your table names and column names.
Neither the Parent table nor the Child table can be a
TEMPORARY
table.Neither the Parent table nor the Child table can be a
PARTITIONED
table.If you declare a FK with the
ON DELETE SET NULL
option, then the FK column(s) must be nullable.If you declare a constraint name for a foreign key, the constraint name must be unique in the whole schema, not only in the table in which the constraint is defined. Two tables may not have their own constraint with the same name.
If there are any other FK's in other tables pointing at the same field you are attempting to create the new FK for, and they are malformed (i.e. different collation), they will need to be made consistent first. This may be a result of past changes where
SET FOREIGN_KEY_CHECKS = 0;
was utilized with an inconsistent relationship defined by mistake. See @andrewdotn's answer below for instructions on how to identify these problem FK's.MySQL 的通用“errno 150”消息“意味着外键约束未正确形成。”如果您正在阅读此页面,您可能已经知道,通用的“errno:150”错误消息确实没有帮助。但是:
您可以通过运行
SHOW ENGINE INNODB STATUS;
获取实际错误消息;,然后在例如,创建外键约束的尝试:
失败,并出现错误
Can't create table 'test.t2' (errno: 150)
。除了这是一个外键问题之外,这并没有告诉任何人任何有用的信息。但是运行SHOW ENGINE INNODB STATUS;
它会说:它说问题是找不到索引。
SHOW INDEX FROM t1
显示表t1
根本没有任何索引。例如,通过在t1
上定义主键来解决此问题,并且外键约束将成功创建。MySQL’s generic “errno 150” message “means that a foreign key constraint was not correctly formed.” As you probably already know if you are reading this page, the generic “errno: 150” error message is really unhelpful. However:
You can get the actual error message by running
SHOW ENGINE INNODB STATUS;
and then looking forLATEST FOREIGN KEY ERROR
in the output.For example, this attempt to create a foreign key constraint:
fails with the error
Can't create table 'test.t2' (errno: 150)
. That doesn’t tell anyone anything useful other than that it’s a foreign key problem. But runSHOW ENGINE INNODB STATUS;
and it will say:It says that the problem is it can’t find an index.
SHOW INDEX FROM t1
shows that there aren’t any indexes at all for tablet1
. Fix that by, say, defining a primary key ont1
, and the foreign key constraint will be created successfully.确保您尝试使用约束链接的两个字段的属性完全相同。
通常,ID 列上的“无符号”属性会让您感到困惑。
Make sure that the properties of the two fields you are trying to link with a constraint are exactly the same.
Often, the 'unsigned' property on an ID column will catch you out.
运行此脚本时数据库的当前状态是什么?它完全是空的吗?从头开始创建数据库时,您的 SQL 对我来说运行良好,但 errno 150 通常与删除 & 有关。重新创建作为外键一部分的表。我感觉您没有使用 100% 全新的数据库。
如果您在“source”SQL 文件时出错,您应该能够在“source”命令之后立即从 MySQL 提示符运行“SHOW ENGINE INNODB STATUS”命令来查看更详细的错误信息。
您可能还想查看手动输入:
What's the current state of your database when you run this script? Is it completely empty? Your SQL runs fine for me when creating a database from scratch, but errno 150 usually has to do with dropping & recreating tables that are part of a foreign key. I'm getting the feeling you're not working with a 100% fresh and new database.
If you're erroring out when "source"-ing your SQL file, you should be able to run the command "SHOW ENGINE INNODB STATUS" from the MySQL prompt immediately after the "source" command to see more detailed error info.
You may want to check out the manual entry too:
对于正在查看此帖子并遇到同样问题的人:
出现此类错误的原因有很多。有关 MySQL 中外键错误的原因和解决方案的相当完整的列表(包括此处讨论的那些),请查看此链接:
MySQL 外键错误和错误号150
For people who are viewing this thread with the same problem:
There are a lot of reasons for getting errors like this. For a fairly complete list of causes and solutions of foreign key errors in MySQL (including those discussed here), check out this link:
MySQL Foreign Key Errors and Errno 150
对于通过 Google 找到此 SO 条目的其他人:请确保您没有尝试对定义为“NOT NULL”的外键(待)列执行 SET NULL 操作。这引起了极大的挫败感,直到我记得检查引擎 INNODB 状态。
For others that find this SO entry via Google: Be sure that you aren't trying to do a SET NULL action on a foreign key (to be) column defined as "NOT NULL." That caused great frustration until I remembered to do a CHECK ENGINE INNODB STATUS.
绝对不是这样的,但我发现这个错误很常见而且不明显。
FOREIGN KEY
的目标可能不是PRIMARY KEY
。对我有用的答案是:外键始终必须指向其他表的主键真实字段。
Definitely it is not the case but I found this mistake pretty common and unobvious. The target of a
FOREIGN KEY
could be notPRIMARY KEY
. Te answer which become useful for me is:A FOREIGN KEY always must be pointed to a PRIMARY KEY true field of other table.
正如 @andrewdotn 所指出的,最好的方法是查看详细的错误(
SHOW ENGINE INNODB STATUS;
),而不仅仅是错误代码。原因之一可能是同名索引已存在,可能位于另一个表中。作为实践,我建议在索引名称之前添加表名称前缀以避免此类冲突。例如,使用
idx_userActionMapping_userId
代替idx_userId
。As pointed by @andrewdotn the best way is to see the detailed error(
SHOW ENGINE INNODB STATUS;
) instead of just an error code.One of the reasons could be that an index already exists with the same name, may be in another table. As a practice, I recommend prefixing table name before the index name to avoid such collisions. e.g. instead of
idx_userId
useidx_userActionMapping_userId
.请首先确保
我也遇到了同样的麻烦,并且已经解决了。我对一个字段有无符号 INT,而对其他字段只有整数。
Please make sure at first that
I had the same trouble and I've fixed it. I had unsigned INT for one field and just integer for other field.
有用的提示,在尝试
CREATE
查询后使用SHOW WARNINGS;
,您将收到错误以及更详细的警告:因此在这种情况下,需要重新创建我的桌子!
Helpful tip, use
SHOW WARNINGS;
after trying yourCREATE
query and you will receive the error as well as the more detailed warning:So in this case, time to re-create my table!
当您尝试将文件源导入现有数据库时,通常会发生这种情况。
首先删除所有表(或数据库本身)。
然后源文件的开头为
SETforeign_key_checks = 0;
,结尾为SETforeign_key_checks = 1;
。This is usually happening when you try to source file into existing database.
Drop all the tables first (or the DB itself).
And then source file with
SET foreign_key_checks = 0;
at the beginning andSET foreign_key_checks = 1;
at the end.我发现了失败的另一个原因......区分大小写的表名。
对于这个表定义
这个表定义有效
,而这个失败
它在 Windows 上有效但在 Unix 上失败这一事实花了我几个小时才弄清楚。希望对其他人有帮助。
I've found another reason this fails... case sensitive table names.
For this table definition
This table definition works
whereas this one fails
The fact that it worked on Windows and failed on Unix took me a couple of hours to figure out. Hope that helps someone else.
适用于 Mac 操作系统的 MySQL Workbench 6.3。
问题:尝试在数据库图上进行正向工程时,表 X 上出现 errno 150,21 次中有 20 次成功,1 次失败。如果表 X 上的 FK 被删除,则错误会转移到之前未发生故障的另一个表。
将所有表引擎更改为 myISAM,它工作得很好。
MySQL Workbench 6.3 for Mac OS.
Problem: errno 150 on table X when trying to do Forward Engineering on a DB diagram, 20 out of 21 succeeded, 1 failed. If FKs on table X were deleted, the error moved to a different table that wasn't failing before.
Changed all tables engine to myISAM and it worked just fine.
还值得检查一下您是否意外地操作了错误的数据库。如果外表不存在,就会出现此错误。为什么 MySQL 必须如此神秘?
Also worth checking that you aren't accidentally operating on the wrong database. This error will occur if the foreign table does not exist. Why does MySQL have to be so cryptic?
确保外键在父级中未列为唯一。我遇到了同样的问题,我通过将其划分为非唯一来解决它。
Make sure that the foreign keys are not listed as unique in the parent. I had this same problem and I solved it by demarcating it as not unique.
就我而言,这是由于作为外键字段的字段名称太长,即。
外键 (some_other_table_with_long_name_id)
。尝试更短一些。在这种情况下,错误消息有点误导。另外,正如 @Jon 之前提到的 - 字段定义必须相同(注意
unsigned
子类型)。In my case it was due to the fact that the field that was a foreign key field had a too long name, ie.
foreign key (some_other_table_with_long_name_id)
. Try sth shorter. Error message is a bit misleading in that case.Also, as @Jon mentioned earlier - field definitions have to be the same (watch out for
unsigned
subtype).(旁注对于评论来说太大)
映射表中不需要
AUTO_INCRMENT
id;摆脱它。将
PRIMARY KEY
更改为(role_id, role_group_id)
(任意顺序)。这将使访问速度更快。由于您可能想要映射两个方向,因此还要添加一个
INDEX
,其中这两列的顺序相反。 (无需使其UNIQUE
。)更多提示:http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta
(Side notes too big for a Comment)
There is no need for an
AUTO_INCREMENT
id in a mapping table; get rid of it.Change the
PRIMARY KEY
to(role_id, role_group_id)
(in either order). This will make accesses faster.Since you probably want to map both directions, also add an
INDEX
with those two columns in the opposite order. (There is no need to make itUNIQUE
.)More tips: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta
当外键约束基于
varchar
类型时,则除了marv 提供的 列表-el
目标列必须具有唯一约束。When the foreign key constraint is based on
varchar
type, then in addition to the list provided bymarv-el
the target column must have an unique constraint.在创建表之前执行以下行:
设置 FOREIGN_KEY_CHECKS = 0;
FOREIGN_KEY_CHECKS 选项指定是否检查 InnoDB 表的外键约束。
-- 指定检查外键约束(这是默认值
)
-- 不检查外键约束
SET FOREIGN_KEY_CHECKS = 0;
何时使用:
当您需要重新创建表并以任何父子顺序加载数据时,暂时禁用引用约束(将 FOREIGN_KEY_CHECKS 设置为 0)非常有用
execute below line before creating table :
SET FOREIGN_KEY_CHECKS = 0;
FOREIGN_KEY_CHECKS option specifies whether or not to check foreign key constraints for InnoDB tables.
-- Specify to check foreign key constraints (this is the default)
-- Do not check foreign key constraints
SET FOREIGN_KEY_CHECKS = 0;
When to Use :
Temporarily disabling referential constraints (set FOREIGN_KEY_CHECKS to 0) is useful when you need to re-create the tables and load data in any parent-child order
我遇到了同样的问题,但我检查发现我没有父表。所以我只是在子迁移之前编辑父迁移。去做就对了。
I encountered the same problem, but I check find that I hadn't the parent table. So I just edit the parent migration in front of the child migration. Just do it.