首页 文章

MySQL使用外键创建表,给出错误:150

提问于
浏览
94

我试图在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 回答

  • 0

    我和 ALTER TABLE ADD FOREIGN KEY 有同样的问题 .

    一小时后,我发现必须满足这些条件才能得到错误150:

    • 在定义引用它的外键之前,父表必须存在 . 您必须按正确的顺序定义表:首先是父表,然后是子表 . 如果两个表互相引用,则必须创建一个没有FK约束的表,然后创建第二个表,然后使用 ALTER TABLE 将FK约束添加到第一个表 .

    • 这两个表必须都支持外键约束,即 ENGINE=InnoDB . 其他存储引擎默默地忽略外键定义,因此它们不返回错误或警告,但不保存FK约束 .

    • Parent表中引用的列必须是键的最左侧列 . 如果父项中的键是 PRIMARY KEYUNIQUE 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列中的值匹配 . 使用如下查询检查:

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

    这必须返回零(0)个不匹配的值 . 显然,这个查询是一个通用的例子;您必须替换您的表名和列名 .

    • Parent表和Child表都不能是 TEMPORARY 表 .

    • Parent表和Child表都不能是 PARTITIONED 表 .

    • 如果使用 ON DELETE SET NULL 选项声明FK,则FK列必须可为空 .

    • 如果声明外键的约束名称,则约束名称在整个模式中必须是唯一的,而不仅仅是在定义约束的表中 . 两个表可能没有自己的具有相同名称的约束 .

    希望这可以帮助 .

  • 3

    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.

    例如,这种尝试创建外键约束:

    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 上定义主键,将成功创建外键约束 .

  • 0

    确保您尝试使用约束链接的两个字段的属性完全相同 .

    通常,ID列上的“unsigned”属性会引起您的注意 .

    ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;
    
  • 1

    运行此脚本时,数据库的当前状态是什么?它完全是空的吗?从头开始创建数据库时,您的SQL运行正常,但是errno 150通常与删除和重新创建属于外键的表有关 . 我感觉你没有使用100%全新的数据库 .

    如果您在“源”处理SQL文件时出错,您应该能够在“source”命令之后立即从MySQL提示符运行命令“SHOW ENGINE INNODB STATUS”以查看更详细的错误信息 .

    您可能还想查看手册条目:

    如果重新创建已删除的表,则它必须具有符合引用它的外键约束的定义 . 它必须具有正确的列名和类型,并且必须在引用的键上具有索引,如上所述早 . 如果不满足这些,MySQL将返回错误号1005并在错误消息中引用错误150 . 如果MySQL从CREATE TABLE语句报告错误号1005,并且错误消息引用错误150,则表创建失败,因为未正确形成外键约束 . - MySQL 5.1参考手册 .

  • 5

    对于正在查看具有相同问题的此线程的人:

    得到这样的错误有很多原因 . 有关MySQL中外键错误的原因和解决方案的完整列表(包括此处讨论的那些),请查看此链接:

    MySQL Foreign Key Errors and Errno 150

  • 1

    对于通过Google找到此SO条目的其他人:确保您没有尝试对定义为“NOT NULL”的外键(待定)列执行SET NULL操作 . 在我记得做CHECK ENGINE INNODB状态之前,这引起了极大的挫败感 .

  • 60

    当然不是这样,但我发现这个错误很常见而且不明显 . FOREIGN KEY 的目标可能不是 PRIMARY KEY . 对我有用的答案是:

    A FOREIGN KEY always must be pointed to a PRIMARY KEY true field of other table.

    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));
    
  • 3

    正如@andrewdotn所指出的,最好的方法是查看详细错误( SHOW ENGINE INNODB STATUS; ),而不仅仅是错误代码 .

    其中一个原因可能是索引已经存在,名称相同,可能在另一个表中 . 作为一种做法,我建议在索引名称前加上表名前缀,以避免此类冲突 . 例如而不是 idx_userId 使用 idx_userActionMapping_userId .

  • 0

    有用的提示,在尝试 CREATE 查询后使用 SHOW WARNINGS; ,您将收到错误以及更详细的警告:

    ---------------------------------------------------------------------------------------------------------+
    | 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)                                                                                                                                                                           |
    +---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+
    

    所以在这种情况下,有时间重新创建我的表!

  • 228

    请先确认一下

    • 您正在使用InnoDB表 .
      FOREIGN KEY的
    • 字段与源字段具有相同的类型和长度(!) .

    我遇到了同样的麻烦,我已经修好了 . 我有一个字段的无符号INT和其他字段的整数 .

  • 2

    当您尝试将文件源文件导入现有数据库时,通常会发生这种情况 . 首先删除所有表(或DB本身) . 然后在源文件开头 SET foreign_key_checks = 0; ,最后 SET foreign_key_checks = 1; .

  • 25

    我发现了这个失败的另一个原因......区分大小写的表名 .

    对于此表定义

    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上失败的事实花了我几个小时来弄明白 . 希望能帮助别人 .

  • 10

    适用于Mac OS的MySQL Workbench 6.3 .

    问题:当在DB图上尝试进行正向工程时,表X上的错误150,21个中的20个成功,1个失败 . 如果删除了表X上的FK,则错误将移至另一个之前未失败的表 .

    将所有表引擎更改为myISAM,它工作得很好 .

    enter image description here

  • 1

    另外值得检查的是,您不会意外地在错误的数据库上运行 . 如果外部表不存在,则会发生此错误 . 为什么MySQL必须如此神秘?

  • 2

    确保外键未在父项中列为唯一键 . 我有同样的问题,我通过将其划分为不唯一来解决它 .

  • 3

    在我的情况下,这是因为作为外键字段的字段名称太长,即 . foreign key (some_other_table_with_long_name_id) . 试试......更短 . 在这种情况下,错误消息有点误导 .

    另外,正如@Jon前面提到的那样 - 字段定义必须相同(注意 unsigned 子类型) .

  • 0

    当foraign键约束基于 varchar 类型时,则除了list provided by marv-el之外 target column must have an unique constraint.

  • -1

    (旁注对评论来说太大了)

    映射表中不需要 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

  • 0

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

相关问题