Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 Reference Manual  /  ...  /  Using Foreign Keys

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) 值。

当操作影响父表中的键值,该值在子表中存在匹配行时,结果取决于ON UPDATEON DELETEFOREIGN KEY子句指定的引用操作。省略ON DELETEON UPDATE子句(如当前子表定义)等同于指定RESTRICT选项,拒绝影响父表中键值有匹配行的操作。

为了演示ON DELETEON UPDATE引用操作,删除子表并重新创建它,以包括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 |
+------+-----------+

更新父表中的ID,改变其为2,使用以下SQL语句:

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 Constraints”