MySQL数据库管理与开发实践教程 (清华电脑学堂)
上QQ阅读APP看书,第一时间看更新

4.3 外键约束

主键用于标识表中的数据,而外键用于记录表之间的联系。一个数据库中的表通常是相互关联的,如学生选课系统中,学生要根据课程表来填写选课表,而选课表根据学生表中的学生编号和课程表中的课程编号来确定每个同学所选的课程。选课表中的学生编号和课程编号即为选课表的外键,引用学生表和课程表中的数据。本节介绍外键约束的概念和使用。

4.3.1 外键约束概述

外键记录了表与表之间字段的联系。以学生选课系统来说,学生选课表中,需要记录选课学生的信息,所选的科目,该科目的学分,该学生考试成绩等。

学生信息所涉及的内容有很多,包括学生姓名、所在班级等信息,而同一个班的学生也有着重名的情况,若将学生的信息放在课程表中,课程表将变得复杂、难以理解,而且并不能够确定每个学生所选的科目究竟是怎样的。

因此需要根据学生表中的主键sid字段,来确定唯一的学生,并放在选课表中作为一个字段。此时,选课表根据该字段的值,可在学生信息表中进行查询,以确定该条记录所属的学生信息,而不需要将学生的详细信息放在选课表中。

同样的道理,选课表中需要有课程信息,包括该课程的名称,所属院系,讲课教师信息等,但在选课表中放这些信息,只能使选课表变得复杂难以理解。因此使用课程表中的课程主键cid来确定课程信息。

总体来说,外键有着以下两个作用。

(1)让数据库自己通过外键来保证数据的完整性和一致性。

(2)能够增加数据库表关系的可读性。

上述第一条作用,通过外键来确保数据的完整性和一致性。以上述选课表为例,该表引用学生表的主键sid字段,在该表中需要有一个字段(假设命名为csid),存储学生sid信息,以便根据学生sid信息查询学生信息。那么,csid字段中的值必须在学生表的sid字段中有记录,而且学生表在删除学生信息时,需要确保选课表中没有该学生的记录。

同样,选课表中关于课程表的信息,在课程表中必须有记录,而且课程表若需要删除时,需要确保选课表中没有该课程,否则将出错。

外键的使用将不同表的字段关联起来,这些数据在修改、删除时有着关联。外键除了关联着表之间的联系,还将在数据操作时维护数据完整性。

外键的定义需要服从下列几种情况。

(1)所有tables必须是InnoDB型,它们不能是临时表。因为在MySQL中只有InnoDB类型的表才支持外键。

(2)所有要建立外键的字段必须建立约束。

(3)对于非InnoDB表,FOREIGN KEY子句会被忽略掉。

对外键的操作包括,添加外键、删除外键、修改外键等,在后面的小节中介绍。

4.3.2 创建外键约束

外键可以在MySQL Workbench中进行创建,也可以使用SQL语句进行创建。外键约束的添加不同于主键约束,因为外键是作用在多个表的基础上。

1.MySQL Workbench添加外键

外键是设计在两个表之间的,一个表的外键大多是另一个表的主键。如水果信息表中有水果负责人编号字段,该字段对应职员信息表中的职员编号(主键)字段。那么对水果信息表设置主键时,除了将水果负责人字段添加外键约束,同时还需要指出该字段所对应的外表字段和字段所在的外表。

【范例5】

向水果信息表fruits中添加外键约束,其中fwid对应work表中的wid字段,步骤如下。

(1)在表fruits名称处右击,选择Alter Table选项打开表的修改界面。在表修改界面的下方,单击Foreign Keys选项,如图4-3所示。

图4-3 设置外键

(2)如图4-3所示,该窗体分为多个区域,在左下方为需要引用的外键名称和需要引用的表,而下部中间位置,是fruits表中的字段和需要引用的字段。在左下方区域中是一个表格,第一列是水果信息表中的外键约束的名称,第二列是该外键所需要引用的表。

外键约束的名称可以自由定义,如fwid字段对应work表中的wid字段,那么外键名称可以定义为fwid_wid。而外键所引用的表必须在该数据库中选择,第二列是以下拉框的形式列出了当前数据库中所有的表。

(3)在界面下部的中间区域中也是一个表格,第一列是水果信息表中的所有字段;第二列以下拉框的形式列出外表中的字段。

如图4-3左侧设置了约束名称是fwid_wid,对应的外表是work表,那么在中间区域第二列的下拉框中将列举work表的字段列表。在第一列选中fruits表的fwid字段;在第二列中选中对应的wid字段即可。

(4)如图4-3所示,在该窗体的右下方区域,需要选择外键约束选项,在控制台中若不声明该选项,则默认是采用RESTRICT方式。对于外键,最好是采用ON UPDATE CASCADE和ON DELETE RESTRICT的方式。

外键约束选项用于表数据修改和删除时,各个关键表中关联数据的处理。其各选项的作用如下所示。

①CASCADE:外键表中外键字段值会跟随父表被更新,或所在的列会被删除。

②NO ACTION:不进行任何关联操作。

③RESTRICT:RESTRICT相当于NO ACTION,即不进行任何操作。拒绝父表修改外键关联列,删除记录。

④SET NULL:在父表的外键关联字段被修改和删除时,外键表的外键列被设置为空(NULL)。

而对于数据的添加,子表的外键列输入的值,只能是父表外键关联列已有的值,否则出错。

(5)单击Apply按钮打开执行对话框;接着单击Apply按钮确认执行SQL语句;最后在弹出的对话框中单击Finish按钮完成数据表的修改。

技巧

在添加外键约束时,将默认为外键添加一个排序索引,索引的名称默认是外键约束的名称后添加“_idx”。若外键本身就有该类型的索引,则省略此步骤。

范例5是在现有的表中添加外键约束,对于新建的表创建外键约束,只需要添加好字段,接着选择界面下方的Foreign Keys选项设置外键,外键的设置步骤与范例5的步骤一样。

2.SQL语句添加外键

添加外键有两种方式,一种是在创建表的时候添加外键;一种是在现有的表中添加外键约束。其语法如下所示:

INDEX '索引名' ('外键字段' ASC),
    CONSTRAINT '外键约束名'
      FOREIGN KEY ('外键字段')
      REFERENCES '外表名称' ('外表对应字段')
      约束选项;

上述代码是创建表的时候,在创建语句之后添加的语句。可以放在字段列表和主键约束定义之后。

【范例6】

创建ftype表,有tid、fid、title和type字段。为fid字段设置外键约束名称为fruit,对应外表fruits表中的fid字段,代码如下。

CREATE TABLE 'fruitshop'.'ftype' (
      'tid' INT NOT NULL,
      'fid' INT NULL,
      'title' VARCHAR(45) NULL,
      'type' VARCHAR(45) NULL,
      PRIMARY KEY ('tid'),
      INDEX 'fruit_idx' ('fid' ASC),
      CONSTRAINT 'fruit'
        FOREIGN KEY ('fid')
        REFERENCES 'fruitshop'.'fruits' ('fid')
        ON DELETE NO ACTION
        ON UPDATE NO ACTION);

范例6是一个在创建表时设置外键的例子。若是对现有的表添加外键约束,需要在CONSTRAINT关键字前添加ADD关键字。

【范例7】

对现有的fruits表进行修改,为fwid字段添加外键约束,对应work表中的wid字段,代码如下。

ALTER TABLE 'fruitshop'.'fruits'
    ADD CONSTRAINT 'fwid_wid'
      FOREIGN KEY ('fwid')
      REFERENCES 'fruitshop'.'work' ('wid')
      ON DELETE NO ACTION
      ON UPDATE NO ACTION;

上述代码是在fwid字段有索引的情况下执行的,若fwid字段没有索引,需要首先为其添加索引,代码如下。

ADD INDEX ' fwid_wid_idx' ('fwid' ASC),

其中,ASC表示数据按照从小到大的顺序排序,是定义索引时需要定义的排序方式,另有DESC表示数据按照从大到小的顺序排序。

MySQL对创建外键要求比较严格,精确到字段的类型和长度,在创建时需要注意以下几点。

(1)字段名及其对应的数据表名称不能有误。

(2)字段类型必须对应。

(3)字段的数据值必须对应。这里要求,外键字段的值在外表所对应的字段中必须存在,否则将创建失败。如范例7中,fruits表fwid字段的值,在work表中的wid字段中必须有相同数据值来对应。

(4)检查字段的约束,除了主键约束和外键约束以外,其他约束必须一致。

(5)检查字符集,为了迁移和使用的方便,尽量使用utf8字符集。

4.3.3 修改外键约束

修改外键约束包括多种情况,如修改当前外键约束的字段所对应的字段、修改当前表的外键字段等。外键约束的修改可以在MySQL Workbench中进行,也可以使用SQL语句进行。使用MySQL Workbench进行修改的方法与表修改的方法一样,对外键的设置可参考创建外键时的设置。

在修改外键之前可使用SHOW CREATE TABLE语句查看表中已有的外键设置,如查看fruitshop.fruits表的外键设置,代码如下。

SHOW CREATE TABLE 'fruitshop'.'fruits' ;

上述代码的执行效果如下所示。

+ ------------- + ------------------------- +
    | Table           | Create Table                |
    + ------------- + ------------------------- +
    | fruits          | CREATE TABLE 'fruits' (
      'fid' int(11) NOT NULL,
      'fname' varchar(45) DEFAULT NULL,
      'fprice' varchar(45) DEFAULT NULL,
      'ftime' varchar(45) DEFAULT NULL,
      'fwid' int(11) DEFAULT NULL,
      PRIMARY KEY ('fid'),
      KEY 'wid_idx' ('fwid'),
      CONSTRAINT 'fwid_wid' FOREIGN KEY ('fwid') REFERENCES 'work' ('wid') ON   DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
    + ------------- + -------------------- +
    1 rows

使用SQL语句对外键约束进行修改,需要首先删除表中已有的外键,再添加新的外键约束来代替。

【范例8】

修改fruits表的外键设置,使fwid字段的外键约束对应workers表中的id字段,代码如下。

ALTER TABLE 'fruitshop'.'fruits'
    DROP FOREIGN KEY 'fwid_wid';
    ALTER TABLE 'fruitshop'.'fruits'
    ADD CONSTRAINT 'fwid_wid'
      FOREIGN KEY ('fwid')
      REFERENCES 'fruitshop'.'workers' ('id')
      ON DELETE RESTRICT
      ON UPDATE RESTRICT;

上述代码可分为两部分,前两条语句是删除了当前的外键;后面的语句是添加新的外键,语法与范例7中添加外键的语法一样。