MySQL 不允许我向表中添加外键。没有错误信息

Nic*_*ing 5 mysql foreign-keys

我使用这个查询:

ALTER TABLE recent_article_entry ADD FOREIGN KEY (`article`) REFERENCES article(`id`);
Run Code Online (Sandbox Code Playgroud)

或这个:

ALTER TABLE recent_article_entry ADD CONSTRAINT fk_rae_article FOREIGN KEY (article) REFERENCES article(id);
Run Code Online (Sandbox Code Playgroud)

它说No errors; 1 row affected, taking 127 ms

哪一行受到影响?

如果我去information_schema.KEY_COLUMN_USAGE,我在那里看不到我新生成的外键。如果我尝试添加到recent_article_entry,则不会强制执行约束。

我很困惑。我试图通过将一些值更改为乱码来调试查询。

所以:

ALTER TABLE sldakjfalksdjf ADD FOREIGN KEY (`article`) REFERENCES article(`id`); 
Run Code Online (Sandbox Code Playgroud)

按预期失败,并且

ALTER TABLE recent_article_entry ADD FOREIGN KEY (`aslkdjfalksjdf`) REFERENCES article(`id`);
Run Code Online (Sandbox Code Playgroud)

按预期失败。

但无论出于何种原因,

ALTER TABLE recent_article_entry ADD FOREIGN KEY (`article`) REFERENCES aslkdjfdkf(`id`); 
Run Code Online (Sandbox Code Playgroud)

成功(以及将引用的列更改为乱码)。我以前做过很多外键。为什么 MySQL 突然忽略我的查询而不创建外键?


编辑应ray的要求,这里是describe语句的输出:

describe recent_article_entry

Field        |Type       |Null|Key|Default|Extra
-------------|-----------|----|---|-------|-----
article      |varchar(55)|NO  |PRI|       |
file_location|varchar(55)|NO  |PRI|       |
Run Code Online (Sandbox Code Playgroud)

describe article

Field         |Type          |Null |Key|Default          |Extra
--------------|--------------|-----|---|-----------------|-----
id            |varchar(55)   |NO   |PRI|                 |
title         |varchar(255)  |YES  |   |NULL             |
author        |varchar(55)   |NO   |MUL|                 |
translator    |varchar(55)   |NO   |MUL|                 |
source        |varchar(1000) |YES  |MUL|0                |
published_flag|tinyint(1)    |NO   |   |                 |
published     |timestamp     |YES  |   |CURRENT_TIMESTAMP|
short_title   |varchar(55)   |YES  |   |NULL             |
Run Code Online (Sandbox Code Playgroud)

describe file_location

Field |Type       |Null |Key|Default          |Extra
------|-----------|-----|---|-----------------|-----
id    |varchar(55)|NO   |PRI|                 |
views |int(11)    |YES  |   |NULL             |
Run Code Online (Sandbox Code Playgroud)

并且版本是5.1.56-log

cod*_*edd 6

可能的原因 - 排序规则和编码

我经常看到 MySQL 在尝试在表之间创建 FK 约束时信息不够丰富。几年前我被烧伤的一个特殊例子是相关列的表排序规则和/或字符串编码。它们必须在两个表中匹配。换句话说,您应该验证如果VARCHAR某个表中的 PK 列A正在使用latin1编码,那么VARCHAR某个表中的 FK 列B也必须使用latin1enconding 而不是其他内容,例如utf8.

在下一节中,我将重现您的基本设置,但我确保表排序规则和列编码相同。就我而言,它们是默认的,但您应该检查自己的数据库表以确定。

可能的原因 - 存储引擎

在旧版本的 MySQL 中(你使用的是 5.1,我使用的是 5.7),默认存储引擎是MyISAM. 该存储引擎 符合 ACID。因此,它不支持外键约束。您必须确保每个表的存储引擎都设置为InnoDB

您可以将其指定为 MySQL 配置文件中的默认值或作为create tableSQL 语句的一部分。目前,这种情况似乎更有可能,因为您说您的查询没有产生错误消息。话虽这么说,我并没有立即回忆起之前的可能性是否产生了消息或保持沉默。

在下一节中,我将展示这工作正常,至少对我来说,包括您提供的查询。

创建表

我尝试为您的表重现一些基础知识,足以在它们之间进行 PK 和 FK 设置。现将其转载如下,包括create声明:

mysql> create table `test`.`article` (
    `id` varchar(55) not null,
    `title` varchar(255) null default null,
    primary key (`id`)
);
Query OK, 0 rows affected (0.42 sec)

mysql> create table `test`.`file_location` (
    `id` varchar(55) not null,
    `views` int(11) null default null,
    primary key (`id`)
);
Query OK, 0 rows affected (0.35 sec)

mysql> create table `test`.`recent_article_entry` (
    `article` varchar(55) not null,
    `file_location` varchar(55) not null,
    primary key (`article`, `file_location`)
);
Query OK, 0 rows affected (0.32 sec)
Run Code Online (Sandbox Code Playgroud)

表格describe如下:

mysql> show tables;
+----------------------+
| Tables_in_test       |
+----------------------+
| article              |
| file_location        |
| recent_article_entry |
+----------------------+
3 rows in set (0.00 sec)

mysql> describe article;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | varchar(55)  | NO   | PRI | NULL    |       |
| title | varchar(255) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> describe file_location;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | varchar(55) | NO   | PRI | NULL    |       |
| views | int(11)     | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> describe recent_article_entry;
+---------------+-------------+------+-----+---------+-------+
| Field         | Type        | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| article       | varchar(55) | NO   | PRI | NULL    |       |
| file_location | varchar(55) | NO   | PRI | NULL    |       |
+---------------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

创建约束

在这里,我们在添加外键之前检查列的使用情况,并注意它们没有显示,因为它们还不存在:

mysql> select TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_SCHEMA, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME from information_schema.KEY_COLUMN_USAGE;
+----------------------+---------------+-------------------------+-----------------------+------------------------+
| TABLE_NAME           | COLUMN_NAME   | REFERENCED_TABLE_SCHEMA | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME |
+----------------------+---------------+-------------------------+-----------------------+------------------------+
| article              | id            | NULL                    | NULL                  | NULL                   |
| file_location        | id            | NULL                    | NULL                  | NULL                   |
| recent_article_entry | article       | NULL                    | NULL                  | NULL                   |
| recent_article_entry | file_location | NULL                    | NULL                  | NULL                   |
+----------------------+---------------+-------------------------+-----------------------+------------------------+
4 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

我继续在测试数据库中使用以下查询创建了 FK:

alter table `test`.`recent_article_entry`
    add constraint `fk_recent_article_entry_article_id`
        foreign key (`article`)
        references `test`.`article` (`id`)
        on delete restrict
        on update cascade,

    add constraint `fk_recent_article_entry_file_location`
        foreign key (`file_location`)
        references `test`.`file_location` (`id`)
        on delete restrict
        on update cascade;
Run Code Online (Sandbox Code Playgroud)

然后我information_schema像以前一样检查了。您现在可以看到列出的约束:

mysql> select TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_SCHEMA, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME from information_schema.KEY_COLUMN_USAGE;
+----------------------+---------------+-------------------------+-----------------------+------------------------+
| TABLE_NAME           | COLUMN_NAME   | REFERENCED_TABLE_SCHEMA | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME |
+----------------------+---------------+-------------------------+-----------------------+------------------------+
| article              | id            | NULL                    | NULL                  | NULL                   |
| file_location        | id            | NULL                    | NULL                  | NULL                   |
| recent_article_entry | article       | NULL                    | NULL                  | NULL                   |
| recent_article_entry | file_location | NULL                    | NULL                  | NULL                   |
| recent_article_entry | article       | test                    | article               | id                     |
| recent_article_entry | file_location | test                    | file_location         | id                     |
+----------------------+---------------+-------------------------+-----------------------+------------------------+
6 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

我知道我的查询看起来与您的查询不同,但您的查询也适合我,正如我接下来将展示的那样。我删除了上面显示的 FK,然后尝试您自己的查询:

mysql> alter table recent_article_entry add foreign key (`article`) references article(`id`);
Query OK, 0 rows affected (0.56 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_SCHEMA, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME from information_schema.KEY_COLUMN_USAGE;
+----------------------+---------------+-------------------------+-----------------------+------------------------+
| TABLE_NAME           | COLUMN_NAME   | REFERENCED_TABLE_SCHEMA | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME |
+----------------------+---------------+-------------------------+-----------------------+------------------------+
| article              | id            | NULL                    | NULL                  | NULL                   |
| file_location        | id            | NULL                    | NULL                  | NULL                   |
| recent_article_entry | article       | NULL                    | NULL                  | NULL                   |
| recent_article_entry | file_location | NULL                    | NULL                  | NULL                   |
| recent_article_entry | article       | test                    | article               | id                     |
+----------------------+---------------+-------------------------+-----------------------+------------------------+
Run Code Online (Sandbox Code Playgroud)

如您所见,您自己的查询对我来说效果很好。如果您还有其他问题或发现您认为我可能错过的内容,请在评论中告诉我。

  • 非常感谢——我的问题是存储引擎。如此愚蠢。在“ALTER TABLE recent_article_entry ENGINE=InnoDB;”之后,一切正常。 (3认同)