4.4.2 not null约束 4.4.3 unique约束 4.4.4 check子句

4.4.2 not null约束

正如我们在第3章中讨论过的,空值是所有域的成员,因此在默认情况下是SQL中每个属性的合法值。然而对于一些属性来说,空值可能是不合适的。
考虑student关系中的一个元组,其中namenull。这样的元组给出了一个未知学生的学生信息;因此它不含有有用的信息。
类似地,我们不会希望系的预算为null

not null约束写法

在这些情况下,我们希望禁止空值,我们可以通过如下声明来通过限定属性namebudget的域来排除空值:

1
2
name varchar(20) not null
budget numeric(12,2) not null

主码不用声明not null

not null声明禁止在该属性上插入空值。任何可能导致向一个声明为not null的属性插入空值的数据库修改都会产生错误诊断信息。
许多情况下我们希望避免空值。尤其是**SQL禁止在关系模式的主码中出现空值。因此,在我们的大学例子中,在department关系上如果声明属性dept_namedepartment的主码,那它就不能为空。因此主码(dept_name)不必显式地声明为not null**

4.4.3 unique约束

SQL还支持下面这种完整性约束:

1
unique(A1,A2,...,An)

unique声明的属性形成候选码

unique声明指出属性A1,A2,...,An形成了一个候选码;
在关系中没有两个元组能在所有列出的属性A1,A2,...,An上取值相同

unique中的属性可以为null

然而候选码属性可以为null,除非它们已被显式地声明为not null
回忆一下,空值不等于其他的任何值。(这里对空值的处理与3.8.4节中定义的unique结构一样。)

4.4.4 check子句

当应用于关系声明时, check(P)子句指定一个谓词P,关系中的每个元组都必须满足谓词P
**通常用check子句用来保证属性值满足指定的条件**。
实际上创建了一个强大的类型系统。例如,在创建关系departmentcreate table命令中的check(budget>0)子句将保证budget上的取值是正数。

实例 在建表时指定check子句

作为另一个例子,考虑如下语句:

1
2
3
4
5
6
7
8
9
10
11
create table section (
course_id varchar(8),
sec_id varchar(8),
semester varchar(6),
year numeric(4,0),
building varchar(15),
room_number varchar(7),
time_slot_id varchar(4),
primary key (course_id, sec_id, semester, year),
check (semester in ('Fall', 'Winter', 'Spring', 'Summer'))
);

这里我们用check子句模拟了一个枚举类型,通过指定semester必须是’Fall‘、 WinterSpring或’ Summer‘中的一个来实现。这样, check子句允许以有力的方式对属性域加以限制。

验证

以下在MySQL 8.0中验证通过

不满足check子句的插入会被拒绝

1
2
insert into section
values('1111','2222','3333',2019,'大楼','4444','5555');

这个插入语句试图向semester属性赋值3333,这不满足check子句的要求,系统会拒绝插入操作.

1
2
mysql> insert into section values('1111','2222','3333',2019,'大楼','4444','5555');
3819 - Check constraint 'section_chk_1' is violated.

满足check子句的插入才会通过

1
2
insert into section
values('1111','2222','Fall',2019,'大楼','4444','5555');
1
2
3
4
5
6
7
8
9
10
mysql> insert into section values('1111','2222','Fall',2019,'大楼','4444','5555');
Query OK, 1 row affected (0.01 sec)

mysql> select * from section;
+-----------+--------+----------+------+----------+-------------+--------------+
| course_id | sec_id | semester | year | building | room_number | time_slot_id |
+-----------+--------+----------+------+----------+-------------+--------------+
| 1111 | 2222 | Fall | 2019 | 大楼 | 4444 | 5555 |
+-----------+--------+----------+------+----------+-------------+--------------+
1 row in set (0.04 sec)

目前check子句谓词不能是子查询

根据SQL标准, check子句中的谓词可以是包括子查询在内的任意谓词。然而,当前还没有一个广泛使用的数据库产品允许check子句包含子查询的谓词。