MySQL:无法建立表格(错误编号:150)


156

我正在尝试导入.sql文件及其在创建表时失败。

这是失败的查询:

CREATE TABLE `data` (
`id` int(10) unsigned NOT NULL,
`name` varchar(100) NOT NULL,
`value` varchar(15) NOT NULL,
UNIQUE KEY `id` (`id`,`name`),
CONSTRAINT `data_ibfk_1` FOREIGN KEY (`id`) REFERENCES `keywords` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;    

我从同一数据库中导出了.sql,删除了所有表,现在我试图导入它,为什么会失败?

MySQL:无法建立表格'./dbname/data.frm'(错误号:150)


1
基本上所有导致此错误的原因,这里都是详尽的资源,查找导致MySQL中的errno 150(和errno 121 /其他外键错误)的原因。
约翰·史密斯

21
我发现这些列必须相同(即使无符号标志也必须匹配)。
贾斯汀·斯基尔斯

3
@JohnSmith ...在哪里?
查尔斯·伍德

3
我建议您阅读这篇博客,其中列出10个可能的原因:verysimple.com/2006/10/22/...
马克·阿梅里奥

@CharlesWood:“ 约翰·史密斯 ... 13年4月6日在19:29见过 ”,这大约是您发表评论的三个月。我担心,直到这个愚蠢的世界的尽头,“地方”的奥秘才会被揭露!:>
trejder 2014年

Answers:


167

MySQL-外键约束文档

如果重新创建已删除的表,则该表必须具有符合引用该表的外键约束的定义。如前所述,它必须具有正确的列名和类型,并且必须在引用的键上具有索引。如果不满足这些条件,MySQL将返回错误1005,并在错误消息中引用错误150,这意味着未正确形成外键约束。同样,如果由于错误150而导致ALTER TABLE失败,这意味着将为更改后的表错误地形成外键定义。


1
一个表中的两列是否可以引用另一表(即PK)中的一列?
尤金(Eugene)

1
@Eugene:两列中的每一列都可以与另一个表中的PK具有外键关系-不能将两列都作为单个外键关系。
OMG小马

1
@OMGPonies:感谢您回答这个问题!..我一直在寻找...我也在这里问了一个问题stackoverflow.com/questions/13487010 / .....虽然我有一些不错的答案,但我想保持一致Whether its possible to write Nested Query for my problem?..我也请您回答我!
Grijesh Chauhan

19
我的错误是主表具有MyISAM和子表InnoDB引擎。当前的create.sql脚本正在对所有表使用InnoDB,但是我安装的非常旧,第一个脚本使用了MyISAM。
Whome

2
@Whome-是的,在这里遇到了同样的问题。
aroth

96

错误150表示您的外键有问题。可能外表上的键不是完全相同的类型吗?


15
谢谢:)对我来说,数据类型是INT,但是一个是无符号的,而另一个不是
Anh Nguyen

6
使用模式生成器时,我经常遇到BIGINTvs。INT
Xeoncross

当外键不是INT值时,我遇到了同样的问题。当外键引用该列时,该列必须为UNIQUE。
PhatHV

62

您可以通过运行SHOW ENGINE INNODB STATUS;然后查找来获取实际的错误消息LATEST FOREIGN KEY ERROR在输出中。

资料来源:来自另一个用户的类似问题的答案


7
这实际上非常有用。它告诉您确切的错误。
Csongor Fagyal 2014年

谢谢。真是可惜,MySQL Workbench没有利用它。
scipilot 2014年

太棒了 这很有帮助。告诉您确切的错误。我的是,已将Column设为NULLABLE,但设置为“ on delete set null”。非常感谢。
Abhishek Saini

如果您在服务器上拥有特权:(
Christopher Smit


25

我认为所有这些正确答案都会误导这个问题。

如果要使用外键还原转储文件,那么实际的答案是在开始还原之前这样做:

SET FOREIGN_KEY_CHECKS=0;

因为还原自然会在外表存在之前就创建一些约束。


这样做对我不起作用,仍然会给出错误。有任何想法吗?
约瑟夫·阿斯特拉罕

24

在某些情况下,如果相关表之间有不同的引擎,则可能会遇到此错误消息。例如,一个表可能正在使用InnoDB,而另一个表正在使用MyISAM。两者必须相同


谢谢-这是我的问题。
scipilot 2014年

那是我的问题。谢谢
thed0ctor 2014年

如果您使用mysqldump创建了innodb表的sql文件,并且将它们导出为myisam talbes,则会发生这种情况。
Amado Martinez

11

错误编号 150表示外键约束失败。您可能在外键依赖的表(table keywords)之前创建此表。首先创建该表,它应该可以正常工作。

如果不是,请删除外键语句并在创建表后添加它-您将获得有关特定约束失败的更有意义的错误消息。


10

有很多事情会导致errno 150出现,因此对于搜索此主题的人们来说,我认为这是一个接近详尽的清单(来源Errno 150的原因):

对于errno 150或errno 121,只需在SHOW ENGINE INNODB STATUS中输入,就有一个称为“最新外来键错误”的部分。在此之下,它将给您非常有用的错误消息,该错误消息通常会立即告诉您问题所在。您需要SUPER特权才能运行它,因此,如果没有该特权,则只需测试以下情形。

1)数据类型不匹配:列的类型必须相同

2)父列未索引(或索引顺序错误)

3)列排序规则不匹配

4)在NOT NULL列上使用SET NULL

5)表排序规则不匹配:即使列排序规则匹配,在某些MySQL版本上,这也可能是一个问题。

6)父表中实际上不存在父列。检查拼写(也许在列的开头或结尾有一个空格)

7)其中一列的索引之一不完整,或者该列对于完整索引而言太长。请注意,MySQL(除非您对其进行了调整)最大单列键长为767个字节(这对应于varchar(255)UTF列)

如果出现errno 121错误,则有以下两种原因:

1)您选择的约束名称已经被使用

2)在某些系统上,语句和表名是否区分大小写。如果您从一台具有不同案例处理规则的服务器转到另一台服务器,这可能会给您带来麻烦。


在某些版本中,如果表不是innodb,则会得到errno 150,但是在某些版本中,它只是默默地失败。
juacala 2015年

谢谢,这太棒了:------------------------ | 最新外键错误| ------------------------ | 您已经定义了SET NULL条件,尽管其中一些| 列定义为NOT NULL。
山姆·克里奇利

8

有时MySQL只是超级愚蠢-我可以理解引起外键的原因..但就我而言,我刚刚删除了整个数据库,但仍然出现错误...为什么?我的意思是,没有数据库了……而且我正在使用的sql-user无法访问服务器上的任何其他数据库……我的意思是,该服务器对于当前用户是“空的”,我仍然得到这个错误?抱歉,但是我想MySQL对我说谎……但是我可以处理它:)只需在您的fucky语句周围添加这两行SQL:

SET FOREIGN_KEY_CHECKS = 0;
# some code that gives you errno: 150
SET FOREIGN_KEY_CHECKS = 1;

现在应该执行sql ...如果您确实有外键问题,它将在您将再次启用检查的行显示给您-这将失败..但是我的服务器很安静:)


如果该列与其所引用的列之间实际上存在差异,则可能会导致问题。例如。假设被引用的列是varchar(200),而引用者是varchar(50),那么当尝试级联时,可能会发生奇怪的行为。我还没有遇到因数据不匹配而发出errno 150的问题。
juacala

有趣的见解@juacala :)对我而言,很有趣的是,每当我遇到这个问题时,我的方法总会解决它……至少到今天为止:D但我们从未停止学习,对吧;)
jebbie 2015年

这实际上帮助我生成了一个脚本liquibase。该脚本可以在MySQL> 5.5上完美运行,但对于5.1版失败。
delbertooo

4

在仔细研究了以上答案并进行了一些试验之后,这是解决MySQL中外键错误(1005-错误150)的有效方法。

为了正确创建外键,所有MySQL要求的是:

  • 所有引用的键必须具有主索引或唯一索引。
  • 再次引用列必须与引用列具有相同的数据类型。

满足这些要求,一切都会很好。


4

将Windows应用程序移植到Linux时遇到此错误。在Windows中,数据库表名称不区分大小写,而在Linux中,它们区分大小写,这可能是由于文件系统的差异。因此,在Windows上表Table1是一样的table1,而在REFERENCES这两个table1Table1的作品。在Linux上,当使用应用程序table1而不是Table1创建数据库结构时,我看到错误#150。当我在Table1引用中输入正确的字符大小写时,它也开始在Linux上工作。因此,如果没有其他帮助,请确保REFERENCES在Linux上使用正确的字符大小写在表名中。


这也是我的情况!将脚本从不区分大小写(OS X)迁移到区分大小写的mysql版本(Debian)。
mircealungu

3

更改表的引擎,仅innoDB支持外键


3

如果在一个CHARSET中创建了PK表,然后在另一个CHARSET中创建了FK表,那么您也可能会收到此错误...我也遇到了此错误,但是在将字符集更改为PK字符集之后,它执行了而没有错误

create table users
(
------------
-------------
)DEFAULT CHARSET=latin1;


create table Emp
(
---------
---------
---------
FOREIGN KEY (userid) REFERENCES users(id) on update cascade on delete cascade)ENGINE=InnoDB, DEFAULT CHARSET=latin1;

3

如果两个表都有一个引用,例如,一个表是Student,另一个表是Education,则可能发生此错误,并且我们希望Education表具有Student表的外键引用。在这种情况下,两个表的列数据类型应相同,否则将产生错误。




3

通常,外键与主键之间的不匹配会导致错误:150。

外键必须具有相同的数据类型作为主键。同样,如果主键无符号的,那么外键也必须是无符号的


3

我有同样的问题。它与表的列Collat​​ionCharacter Set有关。确保两个表上的两列的字符集排序规则必须相同。如果要对此设置外键。示例-如果将外键放在引用用户表的userID列的userImage表的userID列上,则排序规则必须与表两列的utf8_general_ci和字符集utf8相同。通常,在创建表时,mysql从服务器设置中采用这两种配置。


为什么我以前没看过这个诗人!?我花了一个小时找出根本原因。就我而言,这是字符集。引用表和引用表必须具有相同的字符集。
Sujit Joshi

2

请确保您的主键列和引用的列都具有相同的数据类型和属性(无符号,二进制,无符号零填充等)。


2

一个真正的极端情况是您使用MySQL工具(在我的情况下为Sequel Pro)重命名数据库。然后创建一个同名数据库。

这将外键约束保持为相同的数据库名称,因此重命名的数据库(例如,my_db_renamed)在新创建的数据库(my_db)中具有外键约束。

不知道这是否是Sequel Pro中的错误,或者某些用例是否需要这种行为,但是这使我花了一大半时间://


2

我有同样的错误。在我的情况下,导致错误的原因是约束中有一个ON DELETE SET NULL语句,而我将约束放入其定义中的字段具有NOT NULL语句。在字段中允许NULL解决了该问题。


2

从文本文件创建数据库时,我遇到了此类问题。

mysql -uroot -padmin < E:\important\sampdb\createdb.sql
mysql -uroot -padmin sampdb < E:\important\sampdb\create_student.sql
mysql -uroot -padmin sampdb < E:\important\sampdb\create_absence.sql

mysql -uroot -padmin sampdb < E:\important\sampdb\insert_student.sql
mysql -uroot -padmin sampdb < E:\important\sampdb\insert_absence.sql

mysql -uroot -padmin sampdb < E:\important\sampdb\load_student.sql
mysql -uroot -padmin sampdb < E:\important\sampdb\load_absence.sql 

我只是在上面写了几行,Create.bat然后运行bat文件。

我的错误是我的sql文件中执行的顺序顺序。我试图用主键和外键创建表。在运行时,它将搜索参考表,但表不存在。因此它将返回此类错误。

如果使用外键创建表,请检查参考表是否存在。并检查引用表和字段的名称。


换句话说,您试图创建一个表,该表具有指向另一个尚不存在的表的外键。以正确的顺序创建表以解决问题。
文森特

2

我有一个类似的问题,但是我的问题是因为我正在向具有数据的现有表中添加一个新字段,并且新字段引用了父表中的另一个字段,并且具有NOT NULL且没有任何DEFAULT值的定义。-我发现事情不正常的原因是

  1. 在可以应用约束之前,我的新字段需要使用每个记录的父表中的值自动填充空白字段。每次应用约束时,都需要保持表数据的完整性不变。实现约束(外键)后,仍然有一些数据库记录没有父表中的值,这意味着数据已损坏,因此MySQL永远不会强制执行您的约束

重要的是要记住,在正常情况下,如果您提前计划数据库并在数据插入之前实施约束,则可以避免这种特殊情况

避免这种陷阱的更简单方法是

  • 保存数据库表数据
  • 截断表数据(以及表工件,例如索引等)
  • 应用约束
  • 汇入资料

我希望这可以帮助别人


1

也许会有所帮助?主键列的定义应与外键列完全相同。



1

您从子表引用的PARENT表的列必须是唯一的。如果不是,则导致错误号150。


它很可能是值得你在添加一些详细信息-如在特定的列名和表名
乔纳森

1

转储具有单个表的Django mysql数据库时,我遇到了类似的问题。通过将数据库转储到文本文件,使用emacs将有问题的表移至文件末尾并将修改后的sql dump文件导入新实例,我能够解决该问题。

HTH Uwe


1

我已通过使变量接受来纠正了问题 null

ALTER TABLE `ajout_norme` 
CHANGE `type_norme_code` `type_norme_code` VARCHAR( 2 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL

1

当执行一系列MySQL命令时,我遇到了同样的问题。当将外键引用到尚未创建的其他表时,会在创建表期间发生雷击。这是引用之前表存在的顺序。

解决方案:在创建具有外键的子表之前,先创建父表。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.