基础教程系列-约束(二)外键约束

一、什么是参照完整性

在学习外键之前,我们必须先搞懂一个概念,什么是“参照完整性”。

参照的关系中的属性值必须能够在被参照关系找到或者取空值,否则不符合数据库的语义。

在实际操作时如更新、删除、插入一个表中的数据,通过参照引用相互关联的另一个表中的数据,来检查对表的数据操作是否正确,不正确则拒绝操作。

举个例子,有一张员工表,字段为工号、姓名、所属部门。 还有一张部门表,字段为部门编号,部门名称,部门位置。

员工表demo_employee如下

字段名称 字段类型 字段含义 主键/外键
emp_no varchar(20) 工号 主键
name varchar(20) 姓名
dept_id bigint(20) 所属部门ID 外键

部门demo_dept表如下

字段名称 字段类型 字段含义 主键/外键
dept_id varchar(20) 部门ID 主键
name varchar(20) 部门名称
location varchar(100) 地址

每一个员工都应该有一个从属部门,并且这个部门一定在部门表中有数据存在。或者此员工没有任何部门为NULL,例如员工新入职还未分配所属部门的情况。

如果某个员工尹洪亮,数据记录为从属于极光轻学的建筑业务部,但是公司根本就没有这个部门,这就代表违反了参照完整性,相反就是遵从了参照完整性。

二、MySQL的外键

  1. MySQL 外键约束(FOREIGN KEY)用来在两个表的数据之间建立链接,一个表可以有一个或多个外键。

例如员工表有姓名、年龄、性别、所属部门、籍贯几个列,那么可以只有所属部门这一个列是外键,也可以所属部门和籍贯两个列都是外键。

3.png
  1. 一个表的外键可以为空值,若不为空值,则每一个外键的值必须等于另一个表中主键的某个值。

    例如员工表和部门表,员工表的外键,必须依赖于部门表的主键,可以表述为如下关系。

    demo_employee(dept_id)外键->依赖->demo_dept(dept_id)主键

  2. 外键是表的一个字段,不是本表的主键,但对应另一个表的主键。定义外键后,不允许删除另一个表中具有关联关系的行。

    例如某个部门有10名员工,如果要没有把员工调整到其他部门或者遣散就直接撤销部门是不允许的。

  3. 外键的主要作用是保持数据的一致性和完整性。、

三、主表与从表

  1. 主表也叫做父表:对于两个具有关联关系的表而言,相关联字段中主键所在的表就是主表。

  2. 从表也叫做子表:对于两个具有关联关系的表而言,相关联字段中外键所在的表就是从表。

例如,员工表和部门表的关系, 员工表依赖于部门表,所以部门表就是主表,员工表是从表,可以理解为1个部门下有多个员工。

四、如何选取外键约束字段

定义一个外键时,需要遵守下列规则:

  1. 父表必须已经存在于数据库中,或者是当前正在创建的表。如果是后一种情况,则父表与子表是同一个表,这样的表称为自参照表,这种结构称为自参照完整性。

    如下一张员工表,有一个所属主管列,而主管也是一名员工,所以自己要参照自己的表,这就是自参照完整性,也叫表内外键。

5.png
  1. 必须为父表定义主键。

  2. 主键不能包含空值,但允许在外键中出现空值。也就是说,只要外键的每个非空值出现在指定的主键中,这个外键的内容就是正确的。

  3. 在父表的表名后面指定列名或列名的组合。这个列或列的组合必须是父表的主键或候选键。

  4. 外键中列的数目必须和父表的主键中列的数目相同。

  5. 外键中列的数据类型必须和父表主键中对应列的数据类型相同。

五、如何设置外键

5.1 在创建表时设置外键约束

在数据表中创建外键使用 FOREIGN KEY 关键字,具体的语法如下。

[CONSTRAINT <外键名>] FOREIGN KEY 字段名 [,字段名2,…]
REFERENCES <主表名> 主键列1 [,主键列2,…]

其中:

<外键名>为定义的外键约束的名称,一个表中不能有相同名称的外键;

字段名表示子表需要添加外健约束的字段列;

主表名即被子表外键所依赖的表的名称;

主键列表示主表中定义的主键列或者列组合。

示例 1,为了展现表与表之间的外键关系,本例在 demo_db 数据库中创建一个部门表 demo_dept,表结构如下表所示。

mysql> CREATE TABLE demo_dept
    -> (
    -> id INT(11) PRIMARY KEY,
    -> name VARCHAR(22) NOT NULL,
    -> location VARCHAR(50)
    -> );
Query OK, 0 rows affected (0.37 sec)

创建数据表 demo_employee,并在表 demo_employee 上创建外键约束,让它的键 dept_id作为外键关联到表 demo_dept 的主键 id上,编写 SQL 语句和执行结果如下所示。

mysql> CREATE TABLE demo_employee
    -> (
    -> id INT(11) PRIMARY KEY,
    -> name VARCHAR(25),
    -> dept_id INT(11),
    -> salary FLOAT,
    -> CONSTRAINT fk_emp_dept
    -> FOREIGN KEY(dept_id) REFERENCES demo_dept(id)
    -> );
Query OK, 0 rows affected (0.37 sec)
mysql> DESC demo_employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(25) | YES  |     | NULL    |       |
| dept_id| int(11)     | YES  | MUL | NULL    |       |
| salary | float       | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (1.33 sec)

以上语句执行成功之后,在表 demo_employee 上添加了名称为 fk_emp_dept 的外键约束,外键名称为 dept_id,其依赖于主表 demo_dept 的主键 id。

墙裂注意:子表的外键必须关联父表的主键,且关联字段的数据类型必须匹配,如果类型不一样,则创建子表时会出现错误“ERROR 1005(HY000):Can't create table'database.tablename'(errno:150)”。

5.2 在修改表时添加外键约束

在修改数据表时添加外键约束的语法规则为:

ALTER TABLE <数据表名> ADD CONSTRAINT <索引名> FOREIGN KEY (<列名>)  REFERENCES <主表名>(<列名>);

【示例2】修改数据表tb_employee,将字段dept_id设置为外键,与数据表demo_dept的主键id进行关联,输入的SQL语句和运行结果如下所示。

···mysql
mysql> ALTER TABLE tb_employee
-> ADD CONSTRAINT fk_demo_dept
-> FOREIGN KEY(dept_id)
-> REFERENCES demo_dept(id);
Query OK, 0 rows affected (1.38 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> SHOW CREATE TABLE tb_employee\G
*************************** 1. row ***************************
Table: tb_employee
Create Table: CREATE TABLE tb_employee (
id int(11) NOT NULL,
name varchar(30) DEFAULT NULL,
dept_id int(11) DEFAULT NULL,
salary float DEFAULT NULL,
PRIMARY KEY (id),
KEY fk_demo_dept (dept_id),
CONSTRAINT fk_demo_dept FOREIGN KEY (dept_id) REFERENCES demo_dept (id)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.12 sec)
···

5.3 删除外键约束

对于数据库中定义的外键,如果不再需要,可以将其删除。外键一旦删除,就会解除主表和从表间的关联关系,MySQL 中删除外键的语法格式如下:
···mysql
ALTER TABLE <表名> DROP FOREIGN KEY <外键约束名>;
···

示例 3,删除数据表 tb_employee 中的外键约束 fk_demo_dept,编写 SQL 语句和执行结果如下所示。

···mysql
mysql> ALTER TABLE tb_employee
-> DROP FOREIGN KEY fk_demo_dept;
Query OK, 0 rows affected (0.19 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> SHOW CREATE TABLE tb_employee\G
*************************** 1. row ***************************
Table: tb_employee
Create Table: CREATE TABLE tb_employee (
id int(11) NOT NULL,
name varchar(30) DEFAULT NULL,
dept_id int(11) DEFAULT NULL,
salary float DEFAULT NULL,
PRIMARY KEY (id),
KEY fk_demo_dept (dept_id)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.00 sec)
···

可以看到,tb_employee 中已经不存在 FOREIGN KEY,原有的名称为 fk_emp_dept 的外键约束删除成功。

MySQL是日常工作中使用最对的数据库之一,所以必须要要较为深入和全面的掌握,对于高阶人员还要掌握分布式事务、各种数据库锁、传播机制等,如果您想全方面学习MySQL知识。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容