关系完整性是对关系的某种约束,当关系随着时间变化(增删改等操作改变数据库关系表)时应该满足一定的约束条件,通常这些约束条件都依赖于客观事实
关系完整性包含三个方面,分别是
其中实体完整性和参照完整性是关系模型必须满足的约束条件,或者说是所有数据库管理系统都自动支持的约束条件。而用户自定义完整性则是根据不同的应用程序(不同的使用场景)有选择的设置的一些约束条件
实体完整性实际上就是对于主键完整性的约束条件,要求主键不能为空(NULL)。如果主键为空,那么就无法达到唯一标识一个实体的目的了,所以实体完整性应该包含两个约束
实体完整性在SQL语句中使用PRIMARY KEY关键字定义(实际上就是在定义主键)。有两种定义方式,一种是在定义属性的时候将PRIMARY KEY添加到后面,另一种是在定义完所有属性之后使用关键字PRIMARY KEY指出
下面的例子创建一个student表,并将学生id设置为主键(用来设置实体完整性约束)
CREATE TABLE student (
id INT PRIMARY KEY, /* 紧跟在属性定义后面 */
name VARCHAR(20) NOT NULL,
sex ENUM('male', 'female'),
age INT NOT NULL
);
或者
CREATE TABLE student (
id INT,
name VARCHAR(20) NOT NULL,
sex ENUM('male', 'female'),
age INT NOT NULL ,
PRIMARY KEY(id) /* 在定义完所有属性后设置主键 */
);
另外,考虑另一个表student_course,它存储着所有学生的选课信息,只包含学生id和课程id两个属性,那么根据客观事实可知,想要唯一确定这个表中的某一行,就必须同时提供学生id和课程id,也就是说student_course由(学生id,课程id)这个二元组唯一确定,所以它的主键应该包含两个属性
需要注意的是,当主键包含多个字段时,只能采用上述第二种方式定义主键,对于student_course的表定义如下
CREATE TABLE student_course (
student_id INT NOT NULL,
course_id INT NOT NULL,
PRIMARY KEY(student_id, course_id) /* 在所有属性定义完后定义主键 */
);
设置之后,当向student表插入数据时,就必须提供一个独一无二的学生id,任何将学生id设置为NULL或者提供了一个重复的id的操作都会报错
参照完整性是相对于外键而言的,在数据库中,外键常用来关联两个表,它的值要么为NULL,要么就是它参照的那个表的主键值。以社交网络系统中的用户实体和分组实体为例,其中
用户实体定义了一个用户的各种信息,包括
好友分组实体定义了一个分组的信息,包括
这样在查找每个用户的所有分组时只需要将两个表进行联结并且选择用户表的用户id等于分组表的用户id的那几行即可
在上面的设计中,好友分组包含了用户id,它是用户表的主键,像这样的属性被称为外键,它由FOREIGN KEY … REFERENCES关键字定义
CREATE TABLE user (
user_id INT AUTO_INCREMENT PRIMARY KEY,
password VARCHAR(20) NOT NULL,
);
CREATE TABLE groups (
group_id INT AUTO_INCREMENT,
group_name VARCHAR(20) NOT NULL,
user_id INT,
PRIMARY KEY(group_id, group_name),
FOREIGN KEY (user_id) REFERENCES user(user_id)
/* 将user_id定为外键,参照user表中的user_id属性 */
);
对于外键的约束实际上就是对于参照完整性的约束,对于上面的示例而言,groups表中的user_id字段必须在user表中的user_id字段中存在,也就是不能出现在groups中存在一个user_id它在user中没有的情况
当对表进行插入删除时,数据库管理系统会自动检测该约束规则,常见的情况有两种
上述的两种情况被称为发生了不一致,数据库管理系统有以下几种方式可以处理这种问题
对于级联操作,首先重新定义groups表,为外键user_id设置级联
CREATE TABLE groups (
group_id INT AUTO_INCREMENT,
group_name VARCHAR(20) NOT NULL,
user_id INT,
PRIMARY KEY(group_id, group_name),
FOREIGN KEY (user_id) REFERENCES user(user_id) ON DELETE CASCADE
/* 表示当user表的某个user_id被删除后,级联删除掉groups表对应数据 */
);
然后为两个表添加数据
mysql> SELECT * FROM user;
+---------+----------+
| user_id | password |
+---------+----------+
| 1 | 1234567 |
| 2 | 1234567 |
| 3 | 1234567 |
+---------+----------+
mysql> SELECT * FROM groups;
+----------+------------+---------+
| group_id | group_name | user_id |
+----------+------------+---------+
| 1 | 1_group1 | 1 |
| 1 | 1_group2 | 1 |
| 1 | 1_group3 | 1 |
| 2 | 2_group1 | 2 |
+----------+------------+---------+
现在执行删除操作,删除user表中user_id为1的元组,然后查看groups表,发现和user_id相关的数据也全部被删除
mysql> DELETE FROM user WHERE user_id = 1;
Query OK, 1 row affected (0.02 sec)
mysql> SELECT * FROM groups;
+----------+------------+---------+
| group_id | group_name | user_id |
+----------+------------+---------+
| 2 | 2_group1 | 2 |
+----------+------------+---------+
在CREATE TABLE中定义属性时,可以根据应用程序的要求在属性上添加约束条件,即属性限制,包括
比如上述用户表中的密码password属性,很显然不应该允许用户不设置密码,所以在定义这个属性的时候会加上NOT NULL约束
对于CHECK短语,它可以定义在单个属性之后,也可以在所有属性定义完成后再定义,如果是后者,那么条件表达式可以使用任意多个属性进行判断