MySQL 8.4 参考手册  /  ...  /  使用外键

5.6.6 使用外键

MySQL 支持外键,它允许跨表交叉引用相关数据,以及外键约束,这有助于保持相关数据的一致性。

外键关系涉及一个包含初始列值的父表,以及一个包含引用父列值的列值的子表。外键约束是在子表上定义的。

以下示例通过单列外键关联 parentchild 表,并展示了外键约束如何强制执行参照完整性。

使用以下 SQL 语句创建父表和子表

CREATE TABLE parent (
    id INT NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;


CREATE TABLE child (
    id INT,
    parent_id INT,
    INDEX par_ind (parent_id),
    FOREIGN KEY (parent_id)
        REFERENCES parent(id)
) ENGINE=INNODB;

像这样向父表中插入一行

mysql> INSERT INTO parent (id) VALUES ROW(1);

验证数据是否已插入。您可以通过简单地从 parent 中选择所有行来做到这一点,如下所示

mysql> TABLE parent;
+----+
| id |
+----+
|  1 |
+----+

使用以下 SQL 语句向子表中插入一行

mysql> INSERT INTO child (id,parent_id) VALUES ROW(1,1);

插入操作成功,因为父表中存在 parent_id 1。

尝试向子表中插入一行,其中包含父表中不存在的 parent_id 值,将被拒绝并报错,如下所示

mysql> INSERT INTO child (id,parent_id) VALUES ROW(2,2);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails 
(`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) 
REFERENCES `parent` (`id`))

操作失败,因为指定的 parent_id 值在父表中不存在。

尝试从父表中删除先前插入的行也会失败,如下所示

mysql> DELETE FROM parent WHERE id VALUES = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails 
(`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) 
REFERENCES `parent` (`id`))

此操作失败,因为子表中的记录包含引用的 id (parent_id) 值。

当某个操作影响父表中具有子表中匹配行的键值时,结果取决于 FOREIGN KEY 子句的 ON UPDATEON DELETE 子句指定的参照操作。省略 ON DELETEON UPDATE 子句(如当前子表定义中所示)与指定 RESTRICT 选项相同,该选项拒绝影响父表中具有父表中匹配行的键值的操作。

为了演示 ON DELETEON UPDATE 参照操作,请删除子表并重新创建它以包含带有 CASCADE 选项的 ON UPDATEON DELETE 子句。CASCADE 选项在删除或更新父表中的行时自动删除或更新子表中的匹配行。

DROP TABLE child;

CREATE TABLE child (
    id INT,
    parent_id INT,
    INDEX par_ind (parent_id),
    FOREIGN KEY (parent_id)
        REFERENCES parent(id)
        ON UPDATE CASCADE
        ON DELETE CASCADE
) ENGINE=INNODB;

使用此处所示的语句向子表中插入一些行

mysql> INSERT INTO child (id,parent_id) VALUES ROW(1,1), ROW(2,1), ROW(3,1);

验证数据是否已插入,如下所示

mysql> TABLE child;
+------+-----------+
| id   | parent_id |
+------+-----------+
|    1 |         1 |
|    2 |         1 |
|    3 |         1 |
+------+-----------+

使用此处所示的 SQL 语句更新父表中的 ID,将其从 1 更改为 2

mysql> UPDATE parent SET id = 2 WHERE id = 1;

通过从父表中选择所有行来验证更新是否成功,如下所示

mysql> TABLE parent;
+----+
| id |
+----+
|  2 |
+----+

验证 ON UPDATE CASCADE 参照操作是否更新了子表,如下所示

mysql> TABLE child;
+------+-----------+
| id   | parent_id |
+------+-----------+
|    1 |         2 |
|    2 |         2 |
|    3 |         2 |
+------+-----------+

为了演示 ON DELETE CASCADE 参照操作,请从父表中删除 parent_id = 2 的记录;这将删除父表中的所有记录。

mysql> DELETE FROM parent WHERE id = 2;

因为子表中的所有记录都与 parent_id = 2 相关联,所以 ON DELETE CASCADE 参照操作会从子表中删除所有记录,如下所示

mysql> TABLE child;
Empty set (0.00 sec)

有关外键约束的更多信息,请参阅 第 15.1.20.5 节,“FOREIGN KEY 约束”