MySQL 无法创建外键约束
Posted
技术标签:
【中文标题】MySQL 无法创建外键约束【英文标题】:MySQL cannot create foreign key constraint 【发布时间】:2014-02-26 20:41:28 【问题描述】:我在为 mysql 数据库中的现有表创建外键时遇到一些问题。
我有桌子exp
:
+-------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+-------+
| EID | varchar(45) | NO | PRI | NULL | |
| Comment | text | YES | | NULL | |
| Initials | varchar(255) | NO | | NULL | |
| ExpDate | date | NO | | NULL | |
| InsertDate | date | NO | | NULL | |
| inserted_by | int(11) unsigned | YES | MUL | NULL | |
+-------------+------------------+------+-----+---------+-------+
我不想创建一个名为 sample_df
的新表来引用它,使用以下内容:
CREATE TABLE sample_df (
df_id mediumint(5) unsigned AUTO_INCREMENT primary key,
sample_type mediumint(5) unsigned NOT NULL,
df_10 BOOLEAN NOT NULL,
df_100 BOOLEAN NOT NULL,
df_1000 BOOLEAN NOT NULL,
df_above_1000 BOOLEAN NOT NULL,
target INT(11) unsigned NOT NULL,
assay MEDIUMINT(5) unsigned zerofill NOT NULL,
insert_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
inserted_by INT(11) unsigned NOT NULL,
initials varchar(255),
experiment VARCHAR(45),
CONSTRAINT FOREIGN KEY (inserted_by) REFERENCES user (iduser),
CONSTRAINT FOREIGN KEY (target) REFERENCES protein (PID),
CONSTRAINT FOREIGN KEY (sample_type) REFERENCES sample_type (ID),
CONSTRAINT FOREIGN KEY (assay) REFERENCES assays (AID),
CONSTRAINT FOREIGN KEY (experiment) REFERENCES exp (EID)
);
但我得到了错误:
ERROR 1215 (HY000): Cannot add foreign key constraint
为了获得更多信息,我做了:
SHOW ENGINE INNODB STATUS\G
我从中得到的:
FOREIGN KEY (experiment) REFERENCES exp (EID)
):
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.
对我来说,列类型似乎匹配,因为它们都是 varchar(45)。(我也尝试将 experiment
列设置为不为空,但这并没有解决它)所以我想问题一定是那Cannot find an index in the referenced table where the referenced columns appear as the first columns
。但我不太确定这意味着什么,或者如何检查/修复它。有没有人有什么建议? first columns
是什么意思?
【问题讨论】:
在任何答案或问题中,我都没有发现由于字符集的差异而可能发生此错误。谢谢..干杯!!! 另外,请仔细检查您的列排序规则。您的表格可以是 utf8mb4,但该列可以有不同的排序规则! @Watson 字符集在我的情况下,但你得到了我的支持让我思考。 【参考方案1】:只是将这归结为可能的原因,当引用表列具有相同的“类型”但没有相同的签名时,我遇到了这个问题。
在我的例子中,引用的表列是 TINYINT UNSIGNED,而我的引用表列是 TINYINT SIGNED。对齐两列解决了这个问题。
【讨论】:
@austen-hoogen 建议的解决方案解决了我的问题。但由于声誉得分低,我无法对他的解决方案进行投票和评论。在我的情况下,主键是整数、自动递增和无符号。但是外键(引用表的列)是签名类型。我将其更改为未签名并能够成功创建关系。 是的,遇到了同样的问题。我的主键是 BIGINT (20),而我在另一个表中的引用键是 INT (10) 无符号。我们需要确保它们都匹配。 IE。 BIGINT(20),并且在引用表中也应该是BIGINT(20) 谢谢!这个解决方案也解决了我的问题!我计划在第二个表中设置外键和 bigint 的表中有int
。【参考方案2】:
如果引用表和当前表的字符集不同,也会出现此错误。
【讨论】:
在引用表中将 字符集 设置为latin
后,我在 3 小时后再次开始呼吸。
谢谢。这不是一个小问题
这可能会让自己成为一个问题,这感觉很疯狂,但我想旧表不能一次全部升级到 utf-8 或其他东西。我的新表默认为 latin1【参考方案3】:
根据http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html
MySQL 需要外键和引用键的索引,以便 外键检查可以很快并且不需要表扫描。在里面 引用表,必须有外键所在的索引 列按相同顺序列为第一列。
InnoDB 允许外键引用任何索引列或组 列。但是,在引用的表中,必须有一个索引 其中引用的列被列为 相同的顺序。
所以如果引用表中的索引是存在的,并且它是由几列组成的,并且所需的列不是第一个,就会发生错误。
我们的错误原因是由于违反了以下规则:
外键和引用键中的对应列必须 具有相似的数据类型。整数类型的大小和符号必须是 相同。字符串类型的长度不必相同。为了 非二进制(字符)字符串列、字符集和排序规则 必须相同。
【讨论】:
这帮助我获得了复合主键,其中我的外键被定义为第二个(即 CONSTRAINT pk_dataAssetId PRIMARY KEY (assetId, fk_key)。必须将其更改为主键约束中的第一列(即 CONSTRAINT pk_dataAssetId主键(fk_key,assetId)【参考方案4】:正如@Anton 提到的,这可能是因为不同的数据类型。 就我而言,我有主键 BIGINT(20) 并尝试使用 INT(10) 设置前八键
【讨论】:
谢谢!类似的问题,我将 INT(11) 与 INT(11) 一起使用,但一个是主键,因此未签名,而另一个已签名! @MichaelScottCuthbert 相同【参考方案5】:我的是引用表和要创建的表之间的排序规则问题,因此我必须明确设置我引用的键的排序规则类型。
首先我在引用表上运行查询以获取其排序规则类型show table STATUS like '<table_name_here>';
然后我复制了排序规则类型,并在创建查询中明确说明了employee_id 的排序规则类型。就我而言,它是 utf8_general_ci
CREATE TABLE dbo.sample_db
(
id INT PRIMARY KEY AUTO_INCREMENT,
event_id INT SIGNED NOT NULL,
employee_id varchar(45) COLLATE utf8_general_ci NOT NULL,
event_date_time DATETIME,
CONSTRAINT sample_db_event_event_id_fk FOREIGN KEY (event_id) REFERENCES event (event_id),
CONSTRAINT sample_db_employee_employee_id_fk FOREIGN KEY (employee_id) REFERENCES employee (employee_id)
);
【讨论】:
【参考方案6】:在我的例子中,被引用的列没有被声明为主要的或唯一的。
https://***.com/a/18435114/1763217
【讨论】:
【参考方案7】:对我来说,这只是数据库的字符集和排序规则。我更改为 utf8_unicode_ci 并且可以工作
【讨论】:
您能否举例说明如何检查当前字符集/排序规则? @theiralter schema my_database default character set utf8 default collate utf8_general_ci;
【参考方案8】:
在我的情况下,它与 ENGINE 和 COLLATE 不兼容,一旦我添加了 ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
它就可以了
CREATE TABLE `some_table` (
`id` varchar(36) NOT NULL,
`col_id` varchar(36) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_some_table_cols_col_id` FOREIGN KEY (`col_id`) REFERENCES `ref_table` (`id`) ON DELETE CASCADE,
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
【讨论】:
这个答案需要更多的支持。这就是为我解决的问题。【参考方案9】:主键的确切顺序也需要匹配,中间没有多余的列。
我有一个主键设置,其中列 order 实际匹配,但问题是主键中有一个额外的列,它不是引用表的外键的一部分
例如)表 2,列 (a, b, c) -> 表 1,列 (a, b, d, c) -- 失败
我必须对主键列重新排序,以便它们不仅以相同的方式排序,而且中间没有多余的列:
例如)表 2,列 (a, b, c) -> 表 1,列 (a, b, c, d) -- 成功
【讨论】:
【参考方案10】:我也有这个错误。没有一个答案与我有关。在我的例子中,我的 GUI 会自动创建一个主唯一标识符为“未分配”的表。当我尝试创建外键并给我完全相同的错误时,这会失败。需要分配我的主键。
如果您像 id int unique auto_increment
这样编写 SQL 本身,那么您就不会遇到这个问题,但由于某种原因,我的 GUI 会这样做而不是 id int unassigned unique auto_increment
。
希望这可以帮助其他人。
【讨论】:
【参考方案11】:在我的例子中是使用 integer 作为 id 创建的,而引用表默认使用 bigint 创建一个外键。
这在我的 Rails 应用程序中造成了一场噩梦,因为迁移失败但字段实际上是在 DB 中创建的,因此它们显示在 DB 中,但不在 Rails 应用程序的架构中。
【讨论】:
【参考方案12】:在同一约束中多次引用同一列也会产生此Cannot find an index in the referenced table
错误,但在大型表上很难发现。拆分约束,它将按预期工作。
【讨论】:
【参考方案13】:在某些情况下,除了将其定义为主键之外,我还必须使引用的字段具有唯一性。
但我发现,不将其定义为唯一并不会在任何情况下都造成问题。不过,我无法弄清楚这些场景。可能与可空定义有关。
【讨论】:
您是否阅读过 FK 的介绍或手册? FK 引用 UNIQUE; PK 表示 UNIQUE NOT NULL。【参考方案14】:只是为了混合另一种解决方案。我将删除设置为set null
,但我放置外键的字段不可为空,因此使其可空允许创建外键。
正如其他人所说,以下事情可能是一个问题
Field Length - INT -> BIGINT, VARCHAR(20) -> VARCHAR(40)
Unsigned - UNSIGNED -> Signed
Mixed Collations
【讨论】:
在我的例子中,我的引用列被声明为 INT,但被引用的列是 UNSIGNED INT。【参考方案15】:补充一点,我今天也遇到了同样的问题
两个字段都是 int
的长度等,但是,一个是 unsigned
,这足以打破它。
两者都需要声明为unsigned
【讨论】:
【参考方案16】:我在 OnModelCreating 方法中编写这段代码时遇到了同样的问题 我的问题完全解决了,我的表和迁移创建没有错误。请尝试一下
var cascadeFKs = modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetForeignKeys())
.Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade);
foreach (var fk in cascadeFKs)
fk.DeleteBehavior = DeleteBehavior.Restrict;
【讨论】:
【参考方案17】:这主要是因为您所指的旧表没有适合新表的数据类型/排序规则/引擎。检测差异的方法是将旧表转储出去,然后查看数据库如何收集信息以生成转储脚本
mysqldump -uroot -p -h127.0.0.1 your_database your_old_table > dump_table.sql
它会给你足够的信息供你比较
create table your_old_table
(
`id` varchar(32) not null,
) Engine = InnoDB DEFAULT CHARSET=utf8mb3;
这仅在您有权转储表方案时才有效
【讨论】:
以上是关于MySQL 无法创建外键约束的主要内容,如果未能解决你的问题,请参考以下文章