表和表之间可存在引用关系,这在抽象数据到表时,是很常见的。这种联系是通过在表中创建外键(foreign key)来实现的。
比如一个订单,可能关联用户表和产品表,以此来记录谁买了什么产品。
约定两个概念:
父表:被引用的表。
从表:表中有相应的外键引用父表中的字段。
示例:
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)
ON DELETE CASCADE
) ENGINE=INNODB;
这里 parent 为父表,child 为从表。
外键关联表的同步操作
当表和表之间建立起合适的关联后, INSERT 和 UPDATE 操作会自动检查所插入的记录中指定的外键在相应表中是否存在;
建立外键时,可指定 ON UPDATE <action> 和 ON DELETE <action> 子语句来指定发生 UPDATE 和 DELETE 操作时,外键关联表中数据该如何处理。MySQL 中支持五种处理(action):
-
CASCADE :更新或删除父表记录时,自动更新或删除从表中匹配的记录。实际使用时注意不要在父表或从表中对同一列重复定义 ON UPDATE CASCADE 。CASCADE 类型的操作不会激活触发器 (triggers)。
-
SET NULL :更新或删除父表中记录时,将从表中匹配的记录其外键设置为 NULL ,前提时从表中该外键没有指定为 NOT NULL 。
-
RESTRICT :默认为该项。禁用父表中的更新或删除操作,这与缺省 ON DELETE 和 ON UPDATE 子语句效果一样。
-
NO ACTION :来自 SQL 标准中定义的一种操作,与上面 RESTRICT 等效。一些数据库支持延迟检查(deferred check), NO ACTION 便是这种可延迟检查的操作。在 MySQL 中,外键的检查是及时的,所以 NO ACTION 和 RESTRICT 完全等效。
-
SET DEFAULT : MySQL 能够解析识别该动作,但 InnoDB 和 NDB 引擎不支持。
添加外键
创建外键的语法
[CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (col_name, ...)
REFERENCES tbl_name (col_name,...)
[ON DELETE reference_option]
[ON UPDATE reference_option]
reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
文章开头提到的订单表示例:
CREATE TABLE product (
category INT NOT NULL, id INT NOT NULL,
price DECIMAL,
PRIMARY KEY(category, id)
) ENGINE=INNODB;
CREATE TABLE customer (
id INT NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE product_order (
no INT NOT NULL AUTO_INCREMENT,
product_category INT NOT NULL,
product_id INT NOT NULL,
customer_id INT NOT NULL,
<span class="pl-k">PRIMARY KEY</span>(no),
INDEX (product_category, product_id),
INDEX (customer_id),
<span class="pl-k">FOREIGN KEY</span> (product_category, product_id)
<span class="pl-k">REFERENCES</span> product(category, id)
<span class="pl-k">ON</span> <span class="pl-k">UPDATE</span> CASCADE <span class="pl-k">ON DELETE</span> RESTRICT,
<span class="pl-k">FOREIGN KEY</span> (customer_id)
<span class="pl-k">REFERENCES</span> customer(id)
) ENGINE=INNODB;
所以这个关系里有两个父表 customer 和 product ,一个从表 product_order 。
对现有表添加外键可使用如下的语句:
ALTER TABLE tbl_name
ADD [CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (col_name, ...)
REFERENCES tbl_name (col_name,...)
[ON DELETE reference_option]
[ON UPDATE reference_option]
创建外键时可指定 [symbol] ,即给外键取一个名称,这样在其他操作时可以引用,比如删除外键时。
删除外键
同样是通过 ALTER TABLE 语句来完成。
ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;
删除外键时,如果该外键在创建时取了名称,名通过该名称来删除,如果没有,则需要先查询 MySQL 在创建该外键时自动生成的名称 fk_symbol 是什么。可通过 SHOW CREATE TABLE <table_name> 来完成查询。譬如:
mysql> SHOW CREATE TABLE dept_manager\G
*************************** 1. row ***************************
Table: dept_manager
Create Table: CREATE TABLE `dept_manager` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) COLLATE utf8mb4_general_ci NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`),
KEY `dept_no` (`dept_no`),
CONSTRAINT `dept_manager_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE,
CONSTRAINT `dept_manager_ibfk_2` FOREIGN KEY (`dept_no`) REFERENCES `departments` (`dept_no`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
1 row in set (0.00 sec)
相关资源
|