5.6.6 使用外键
MySQL 支持外键,允许跨表之间的相关数据引用,并且外键约束帮助保持相关数据的一致性。
一个外键关系涉及到父表,它包含初始列值,而子表则包含引用父列值的列值。外键约束是在子表上定义的。
以下示例通过单个列外键来关联 parent
和 child
表,并展示了外键约束如何强制引用完整性。
使用以下 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 UPDATE
和ON DELETE
FOREIGN KEY
子句指定的引用操作。省略ON DELETE
和ON UPDATE
子句(如当前子表定义)等同于指定RESTRICT
选项,拒绝影响父表中键值有匹配行的操作。
为了演示ON DELETE
和ON UPDATE
引用操作,删除子表并重新创建它,以包括ON UPDATE
和ON 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”。