40

我正在使用 MySQL Workbench 制作一个小型数据库。我有一个名为“Immobili”的主表,它的主键由四列组成:(Comune、Via、Civico、Immobile)。

我还有其他三个表,它们具有相同的主键(Comune、Via、Civico、Immobile),但这些字段也引用了表 Immobili。

第一个问题:我可以制作一个也是外键的主键吗?

第二个问题:当我尝试导出更改时,它说:

Executing SQL script in server

# ERROR: Error 1005: Can't create table 'dbimmobili.condoni' (errno: 150)

CREATE  TABLE IF NOT EXISTS `dbimmobili`.`Condoni` (

  `ComuneImmobile` VARCHAR(50) NOT NULL ,
  `ViaImmobile` VARCHAR(50) NOT NULL ,
  `CivicoImmobile` VARCHAR(5) NOT NULL ,
  `InternoImmobile` VARCHAR(3) NOT NULL ,
  `ProtocolloNumero` VARCHAR(15) NULL ,
  `DataRichiestaSanatoria` DATE NULL ,
  `DataSanatoria` DATE NULL ,
  `SullePartiEsclusive` TINYINT(1) NULL ,
  `SullePartiComuni` TINYINT(1) NULL ,
  `OblazioneInEuro` DOUBLE NULL ,
  `TecnicoOblazione` VARCHAR(45) NULL ,
  `TelefonoTecnico` VARCHAR(15) NULL ,
  INDEX `ComuneImmobile` (`ComuneImmobile` ASC) ,
  INDEX `ViaImmobile` (`ViaImmobile` ASC) ,
  INDEX `CivicoImmobile` (`CivicoImmobile` ASC) ,
  INDEX `InternoImmobile` (`InternoImmobile` ASC) ,

  PRIMARY KEY (`ComuneImmobile`, `ViaImmobile`, `CivicoImmobile`, `InternoImmobile`) ,

  CONSTRAINT `ComuneImmobile`
    FOREIGN KEY (`ComuneImmobile` )
    REFERENCES `dbimmobili`.`Immobile` (`ComuneImmobile` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,

  CONSTRAINT `ViaImmobile`
    FOREIGN KEY (`ViaImmobile` )
    REFERENCES `dbimmobili`.`Immobile` (`ViaImmobile` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,

  CONSTRAINT `CivicoImmobile`
    FOREIGN KEY (`CivicoImmobile` )
    REFERENCES `dbimmobili`.`Immobile` (`CivicoImmobile` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,

  CONSTRAINT `InternoImmobile`
    FOREIGN KEY (`InternoImmobile` )
    REFERENCES `dbimmobili`.`Immobile` (`InternoImmobile` )
    ON DELETE CASCADE
    ON UPDATE CASCADE
) ENGINE = InnoDB

显示引擎状态:

表 dbimmobili/valutazionimercato 的外键约束错误:

在被引用的表中找不到索引,其中被引用的列显示为第一列,或者表中的列类型与被引用的表不匹配约束。请注意,使用 >= InnoDB-4.1.12 创建的表中 ENUM 和 SET 的内部存储类型发生了变化,并且旧表中的此类列不能被新表中的此类列引用。

我在哪里做错了?

4

17 回答 17

52

创建外键约束时,MySQL 需要引用表和被引用表上的可用索引。如果引用表上的索引不存在,则会自动创建索引,但被引用表上的索引需要手动创建(Source)。你的好像不见了。

测试用例:

CREATE TABLE tbl_a (
    id int PRIMARY KEY,
    some_other_id int,
    value int
) ENGINE=INNODB;
Query OK, 0 rows affected (0.10 sec)

CREATE TABLE tbl_b (
    id int PRIMARY KEY,
    a_id int,
    FOREIGN KEY (a_id) REFERENCES tbl_a (some_other_id)
) ENGINE=INNODB;
ERROR 1005 (HY000): Can't create table 'e.tbl_b' (errno: 150)

但是如果我们在 上添加一个索引some_other_id

CREATE INDEX ix_some_id ON tbl_a (some_other_id);
Query OK, 0 rows affected (0.11 sec)
Records: 0  Duplicates: 0  Warnings: 0

CREATE TABLE tbl_b (
    id int PRIMARY KEY,
    a_id int,
    FOREIGN KEY (a_id) REFERENCES tbl_a (some_other_id)
) ENGINE=INNODB;
Query OK, 0 rows affected (0.06 sec)

这在大多数情况下通常不是问题,因为被引用的字段通常是被引用表的主键,并且主键会自动建立索引。

于 2010-10-31T12:58:16.277 回答
32

仔细检查外键是否与您在此表中的字段具有完全相同的类型。例如,两者都应该是 Integer(10) 或 Varchar (8),甚至是字符数。

于 2010-10-31T12:55:40.810 回答
16

我意识到这是一篇旧帖子,但它在谷歌中排名很高,所以我添加了我为我的问题找到的内容。如果你有混合的表类型(例如 MyISAM 和 InnoDB),你也会得到这个错误。在这种情况下,InnoDB 是默认的表类型,但是一个表需要全文搜索,所以它被迁移到了 MyISAM。在这种情况下,您无法在引用 MyISAM 表的 InnoDB 表中创建外键。

于 2013-04-18T13:23:27.620 回答
9

如果您的键是 CHAR/VARCHAR 或该类型的东西,另一个可能的问题是不同的排序规则。检查字符集是否相同。

于 2013-06-12T10:44:32.280 回答
9

我有这个错误,并在我的案例中找到了错误的原因。我仍在回复这篇旧帖子,因为它在 Google 上的排名很高。

我要链接的两个列的变量都是整数,但其中一个整数已选中“无符号”。只需取消选中即可修复我的错误。

于 2014-04-15T09:47:01.077 回答
5

我遇到了同样的错误。我发现我在主表中将主键创建为 BIGINT UNSIGNED 并将其声明为第二个表中的外键仅作为 BIGINT 的解决方案。

当我在第二个表中将我的外键声明为 BIGINT UNSIGED 时,一切正常,甚至不需要创建任何索引。

所以这是主键和外键之间的数据类型不匹配:)

于 2012-05-22T11:51:26.050 回答
4

我有完全相同的问题,但我的问题的解决方案完全不同。我在数据库的其他地方有一个同名的外键。这导致了错误 1005。

将我的外键重命名为更特定于该情况的东西解决了这个问题。

于 2013-03-12T09:11:16.817 回答
3
  1. 确保两个表都使用相同的引擎类型。
  2. 确保您要索引的字段具有相同的类型和长度。
于 2015-04-30T16:19:04.287 回答
3

在我的情况下,错误是由于referencingtable is MyISAMwhere as referringtable was造成的InnoDB

Converted表引擎MyISAM to InnoDB为我解决了这个问题。

ALTER TABLE table_name ENGINE=InnoDB;
于 2016-03-24T20:54:17.897 回答
1

我还没有声望投票史蒂夫的建议,但它解决了我的问题。

就我而言,我收到了这个错误,因为这两个表是使用不同的数据库引擎创建的——一个是 Innodb,另一个是 MyISAM。

您可以使用以下命令更改数据库类型:ALTER TABLE t ENGINE = MISAM;

@see http://dev.mysql.com/doc/refman/5.1/en/storage-engine-setting.html

于 2013-07-29T03:16:29.030 回答
1

创建表时要注意CHARSETCOLLATE参数。就 FOREIGN KEY问题而言,如下所示:

CREATE TABLE yourTableName (
....
....
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

就我而言,我无法使用 FOREIGN KEY 引用创建表。首先,我得到了几乎什么也没说的错误代码 1005。然后我添加了 COLLATE,最后添加了抱怨 CHARSET 的错误消息。

Error Code: 1253. COLLATION 'utf8_unicode_ci' is not valid for CHARACTER SET 'latin1'

在那次更正之后,我的问题得到了解决。

于 2016-01-20T14:36:11.717 回答
0

这不是您的具体情况,但对于其他任何人来说,值得注意的是,如果您尝试引用表中的某些字段而不是该表的整个主键,则可能会发生此错误。显然这是不允许的。

于 2011-11-14T10:19:43.763 回答
0

当主键有 2 列时,它们构成复合主键,因此您必须确保在被引用的表中也有 2 列具有相同的数据类型。

于 2012-01-17T07:52:30.000 回答
0

如果有人在 FK/PK 关系看似良好的情况下出现此错误,并且您使用了可视化工具,请尝试删除有问题的 fk 列并在工具中重新添加它们。我不断收到此错误,直到我重新绘制了清除问题的连接。

于 2012-08-13T00:38:39.253 回答
0

对我来说,我试图将子表中的常规索引字段与父表中的主键匹配,默认情况下,一些 MySQL 前端 GUI(如 Sequel Pro)将主键设置为无符号,所以你必须确保子表字段也未签名(除非这些字段可能包含负整数,否则请确保它们都已签名)。

于 2014-03-05T15:11:41.967 回答
0

MySQL 是出了名的脾气暴躁,尤其是在外键和触发器方面。我现在正在微调一个这样的数据库,并遇到了这个问题。它不是不言自明或直观的,所以在这里:

除了检查要在关系中引用的两列是否具有相同的数据类型外,还必须确保要引用的表上的列是索引。如果您使用的是 MySQL Workbench,请选择“列”旁边的“索引”选项卡,并确保外键引用的列是索引。如果没有,请创建一个,将其命名为有意义的名称,并为其指定类型“INDEX”。

一个好的做法是清理关系中涉及的表,以确保以前的尝试没有创建您不想要或不需要的索引。

我希望它有所帮助,一些 MySQL 错误令人抓狂。

于 2015-03-21T18:20:04.977 回答
0

第一个问题:我可以制作一个也是外键的主键吗?

是的。事实上,对于 MySQL 工作台,我已经养成了只使用主键作为外键的习惯。确实减少了收到的随机错误,例如问题中所述的 err:150 。

# ERROR: Error 1005: Can't create table 'dbimmobili.condoni' (errno: 150)

这确实与索引有关,或者更具体地说,MySQL 工作台如何解释和使用它们。如果你在同一个正向工程操作中对模型进行了很多更改(例如外键、索引、col 顺序),这真的会让人感到困惑,尤其是在另一端已经有数据库的情况下。例如,我不认为自动创建的索引在删除外键后会自动删除。

这是我为解决您的接收错误所做的工作。请注意,这似乎很麻烦,但与我使用其他方法所花费的时间相比,它不是。

1.将查找表中的所有外键设为主键(1对多)。

在我的情况下,这涉及将 id 作为 pk 更改为 tbl_users 中的用户名,更改为 tbl_companies 中的用户名和公司,以及更改 tbl_company_contacts 中的用户名和公司和联系人。这是一个供多个用户输入多个公司联系人的应用程序,允许重叠和隐藏其他用户的联系人。

2、删除所有图关系和所有非主键的表索引。

这修复了大多数由错误的 MySQL 工作台引起的索引问题。

3.如果您从头到尾都这样做,请将模式放在服务器上,这样 mysql 工作台就不会对现有索引感到困惑,也不会在模型中缺少索引(问题是由 bby 索引和外键关系引起的,而不是单独的索引)。

这减少了数据库、服务器和 Mysql 工作台必须做出的大量决策。这些关于如何转发工程的决策是复杂而智能的,但并不完美。

4. 现在,我认为这又回到了原点(通常是在设计太快而没有分步过程之后)。我仍然有所有的桌子,但在这个阶段它们是干净的。现在你只需:

首先,正向工程只是为了确保表(没有关系)按预期工作。

通过主键沿着关系链向下,从最顶层的表开始(我的情况是 tbl_users 到 tbl_companies)。在每个关系之后,总是进行正向工程以确保它运行,然后保存模型并关闭,然后对模型进行逆向工程以确保它可以运行。这使您可以在问题出现时快速隔离问题,在我的情况下,旧的已删除外键使用的遗留索引(发生了 2-3 次)。

和 tadda,回到你需要去的地方。

于 2016-02-25T17:57:07.010 回答