介绍
约束:constraint
在创建表的时候,可以给表中的字段加上约束来保证表中数据的完整性,有效性。
常见约束
非空约束not null
非空约束not null约束的字段不能为NULL。
只有列级约束。
示例
mysql> create table t_vip(id int,name varchar(255) not null);
Query OK, 0 rows affected (0.25 sec)
mysql> desc t_vip;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(255) | NO | | NULL | |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.04 sec)
mysql> insert into t_vip(id,name) values(1,'kd');
Query OK, 1 row affected (0.04 sec)
mysql> insert into t_vip(id,name) values(2,'hl');
Query OK, 1 row affected (0.04 sec)
mysql> insert into t_vip(id) values(2);
1364 - Field 'name' doesn't have a default value
可以看到name没有默认值,表示不能为空。
唯一性约束unique
唯一性约束unique约束的字段不能重复,但是可以为NULL。
示例1 列级约束
mysql> create table t_vip(id int,name varchar(255) unique,email varchar(255));
Query OK, 0 rows affected (0.65 sec)
mysql> insert into t_vip(id,name,email) values(1,'kd','[email protected]');
Query OK, 1 row affected (0.08 sec)
mysql> select * from t_vip;
+----+------+------------+
| id | name | email |
+----+------+------------+
| 1 | kd | [email protected] |
+----+------+------------+
1 row in set (0.03 sec)
mysql> insert into t_vip(id,name,email) values(2,'kd','[email protected]');
1062 - Duplicate entry 'kd' for key 't_vip.name'
mysql> insert into t_vip(id) values(2);
Query OK, 1 row affected (0.07 sec)
mysql> select * from t_vip;
+----+------+------------+
| id | name | email |
+----+------+------------+
| 1 | kd | [email protected] |
| 2 | NULL | NULL |
+----+------+------------+
2 rows in set (0.03 sec)
可以看出,name字段被unique约束,不能重复,一旦重复后会出现如下报错:
1062 - Duplicate entry 'kd' for key 't_vip.name'
但是,name字段可以为NULL,而NULL可以重复。
示例2 表级约束
需求:name和email两个字段联合起来具有唯一性
mysql> create table t_vip(
id int,
name varchar(255),
email varchar(255),
unique(name,email));
Query OK, 0 rows affected (0.32 sec)
mysql> desc t_vip;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(255) | YES | MUL | NULL | |
| email | varchar(255) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.03 sec)
mysql> insert into t_vip(id,name,email) values
(1,'kd','[email protected]');
Query OK, 1 row affected (0.05 sec)
mysql> insert into t_vip(id,name,email) values
(2,'kd','[email protected]');
Query OK, 1 row affected (0.04 sec)
mysql> insert into t_vip(id,name,email) values
(3,'kd1','[email protected]');
Query OK, 1 row affected (0.03 sec)
mysql> insert into t_vip(id,name,email) values(4,'kd','[email protected]');
1062 - Duplicate entry '[email protected]' for key 't_vip.name'
从上面的示例中,可以看出两个字段联合的唯一性约束中,两个字段可以分别不同,只有两个字段完全一样的时候才会报错。
主键约束(primary key,简称pk)
主键字段:添加了主键约束的字段。
主键值:主键字段中的每一个值,每一行记录的唯一标识。
任何一张表都应该有主键。
主键值一般都是定长的,使用int,bigint,char等,不建议使用varchar。
特征
主键值不能为NULL,也不能重复(not null + unique)。
列级约束写法—单一主键
mysql> drop table if exists t_vip;
Query OK, 0 rows affected (0.23 sec)
mysql> create table t_vip(
id int primary key,
new varchar(255));
Query OK, 0 rows affected (0.25 sec)
mysql> insert into t_vip(id, new) values(1,'kd');
Query OK, 1 row affected (0.08 sec)
mysql> insert into t_vip(id, new) values(2,'kd1');
Query OK, 1 row affected (0.06 sec)
mysql> insert into t_vip(id, new) values(2,'kd2');
1062 - Duplicate entry '2' for key 't_vip.PRIMARY'
mysql> insert into t_vip(new) values('kd2');
1364 - Field 'id' doesn't have a default value
mysql> select * from t_vip;
+----+-----+
| id | new |
+----+-----+
| 1 | kd |
| 2 | kd1 |
+----+-----+
2 rows in set (0.02 sec)
从上面的代码中可以看出,主键值不能为空,也不能重复,不然会报错。
表级约束写法
主要给多个字段联合起来添加约束(复合主键:两个及以上的字段做主键)—使用较少。
mysql> create table t_vip(
id int,
new varchar(255),
primary key(id));
Query OK, 0 rows affected (0.45 sec)
mysql> insert into t_vip(id, new) values(1,'kd');
Query OK, 1 row affected (0.05 sec)
mysql> insert into t_vip(id, new) values(1,'kd2');
1062 - Duplicate entry '1' for key 't_vip.PRIMARY'
自然主键
主键值是一个自然数,在实际开发中用的多,只要不重复就行,不需要有意义。
业务主键
主键值和业务紧密关联,例如用银行卡账号做主键。
当业务发生变动时,可能影响主键值。
自动维护主键方法
create table t_vip(
id int primary key auto_increment,
name varchar(255)
);
在创建表的时候,使用auto_increment(自增,类型为int,bigint)即可。
外键约束(foreign key,简称fk)
术语
外键字段:添加了外键约束的字段。
外键值:外键字段中的每一个值。
MySQL 外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。对于两个具有关联关系的表而言,相关联字段中主键所在的表就是主表(父表),外键所在的表就是从表(子表)。
外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。比如,一个水果摊,只有苹果、桃子、李子、西瓜等 4 种水果,那么,你来到水果摊要买水果就只能选择苹果、桃子、李子和西瓜,其它的水果都是不能购买的。
主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。一个表可以有一个或多个外键,外键可以为空值,若不为空值,则每一个外键的值必须等于主表中主键的某个值。
定义外键时,需要遵守下列规则:
- 主表必须已经存在于数据库中,或者是当前正在创建的表。如果是后一种情况,则主表与从表是同一个表,这样的表称为自参照表,这种结构称为自参照完整性。
- 必须为主表定义主键。
- 主键不能包含空值,但允许在外键中出现空值。也就是说,只要外键的每个非空值出现在指定的主键中,这个外键的内容就是正确的。
- 在主表的表名后面指定列名或列名的组合。这个列或列的组合必须是主表的主键或候选键。
- 外键中列的数目必须和主表的主键中列的数目相同。
- 外键中列的数据类型必须和主表主键中对应列的数据类型相同。
- 删除表:先删除子表,后删除父表
- 创建表:先创建父表,后创建子表
- 删除数据:先删除子表中的数据,再删除父表中的数据
- 插入数据:先插入父表中,再插入子表中
示例
业务背景:
设计数据库表,来描述“班级和学生”的信息。
第一种方案:班级和学生存储在一张表中
t_student
no(pk) name classno classname
1 jack 101 一班
2 lili 101 一班
3 lilei 102 二班
4 zhangsan 102 二班
上面的方案会造成数据冗余,空间浪费。
第二种方案:一张班级表,一张学生表
t_class 班级表
classno(pk) classname
101 一班
102 二班
t_student 学生表
no(pk) name cno(班级编号,FK——引用t_class表的classno)
1 jack 101
2 lili 101
3 lilei 102
4 zhangsan 102
对于上面学生表中的班级编号字段,需要有约束来让班级编号和班级表中的主键classno联系起来,让班级编号只能取classno中的值(101和102)。
这里cno有外键约束,cno字段为具有外键约束的字段。
代码:
创建t_class和t_student表
mysql> create table t_class(classno int primary key,classname varchar(255));
Query OK, 0 rows affected (0.27 sec)
mysql> create table t_student(
no int primary key auto_increment,
name varchar(255),
cno int,
foreign key(cno) references t_class(classno)//外键约束
);
Query OK, 0 rows affected (0.42 sec)
mysql> desc t_student;
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| no | int | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| cno | int | YES | MUL | NULL | |
+-------+--------------+------+-----+---------+----------------+
3 rows in set (0.03 sec)
插入数据
mysql> insert into t_class(classno,classname) values(101,'一班');
Query OK, 1 row affected (0.05 sec)
mysql> insert into t_class(classno,classname) values(102,'二班');
Query OK, 1 row affected (0.07 sec)
mysql> select * from t_class;
+---------+-----------+
| classno | classname |
+---------+-----------+
| 101 | 一班 |
| 102 | 二班 |
+---------+-----------+
2 rows in set (0.04 sec)
mysql> insert into t_student(name,cno) values('jack',101);
Query OK, 1 row affected (0.08 sec)
mysql> insert into t_student(name,cno) values('lili',101);
Query OK, 1 row affected (0.04 sec)
mysql> insert into t_student(name,cno) values('lilei',102);
Query OK, 1 row affected (0.04 sec)
mysql> insert into t_student(name,cno) values('zhangsan',102);
Query OK, 1 row affected (0.04 sec)
mysql> select * from t_student;
+----+----------+-----+
| no | name | cno |
+----+----------+-----+
| 1 | jack | 101 |
| 2 | lili | 101 |
| 3 | lilei | 102 |
| 4 | zhangsan | 102 |
+----+----------+-----+
4 rows in set (0.03 sec)
然后查看t_student表中相关外键可以取到的值,如下图所示:
只有t_class主键classno中的两个值可以取。
检查约束
check(mysql没有,Oracle有)
not null和unique联合
mysql> create table t_vip(
id int,
name varchar(255) not null unique);
Query OK, 0 rows affected (0.26 sec)
mysql> desc t_vip;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(255) | NO | PRI | NULL | |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.03 sec)
可以看出,name是not null 和unique联合约束后,name变成了主键primary key。(注意:Oracle中不一样!)