1、概念:约束是作用于表中字段上的规则,用于限制储存在表中的数据
2、目的:保证数据库中的数据的正确性,有效性和完整性
3、分类
需求1:创建一个表id、name、age、address、stu_num五个字段。
需求2:id字段为主键,且设置为自动递增。
需求3:name字段长度为10个字符并且不能为空。
需求4:age字段要大于0并且小于150.
需求5:address字段如果不设,默认为广州。
需求6:stu_num唯一且不能为空。
mysql> create table stu_table( -> id int primary key auto_increment comment "id主键", -> name varchar(10) not null comment "姓名", -> age int check(age>0 && age<150) comment "年龄", -> address varchar(10) default "广州" comment "地址", -> stu_num int not null unique comment "学号" -> ) comment "学生表"; Query OK, 0 rows affected, 1 warning (0.03 sec)
stu_table的表结构如下
mysql> desc stu_table; +---------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+---------+----------------+ | id | int | NO | PRI | NULL | auto_increment | | name | varchar(10) | NO | | NULL | | | age | int | YES | | NULL | | | address | varchar(10) | YES | | 广州 | | | stu_num | int | NO | UNI | NULL | | +---------+-------------+------+-----+---------+----------------+ 5 rows in set (0.01 sec)
说明:
mysql> insert into stu_table (name, age, address, stu_num) values ("张三", 18, "深圳",10001); Query OK, 1 row affected (0.00 sec) mysql> select * from stu_table; +----+--------+------+---------+---------+ | id | name | age | address | stu_num | +----+--------+------+---------+---------+ | 1 | 张三 | 18 | 深圳 | 10001 | +----+--------+------+---------+---------+ 1 row in set (0.00 sec)
说明1:各个字段都复合各个字段的要求,添加正常没有问题
mysql> insert into stu_table (name, age, address, stu_num) values ("ABCDEFGHIJK", 18, "深圳",10002); ERROR 1406 (22001): Data too long for column 'name' at row 1
说明2:直接报错,提示 name data too long 太长了
mysql> insert into stu_table (name, age, address, stu_num) values ("李四", 152, "深圳",10003); ERROR 3819 (HY000): Check constraint 'stu_table_chk_1' is violated.
说明3:这里提示了一个验证错误
mysql> insert into stu_table (name, age, stu_num) values ("李四", 19,10002); Query OK, 1 row affected (0.01 sec) mysql> select * from stu_table; +----+--------+------+---------+---------+ | id | name | age | address | stu_num | +----+--------+------+---------+---------+ | 1 | 张三 | 18 | 深圳 | 10001 | | 2 | 李四 | 19 | 广州 | 10002 | +----+--------+------+---------+---------+ 2 rows in set (0.00 sec)
说明4:在上面的insert 语句中只设置了name,age,stu_num三个字段,所以adderss就自动设置了默认值广州
mysql> insert into stu_table (name, age, address, stu_num) values ("王五", 21, "上海",10002); ERROR 1062 (23000): Duplicate entry '10002' for key 'stu_table.stu_num'
说明5:提示10002已经重复了
说明1:《学生表》和《辅导员》表示两张相互独立的表。
说明2:在《学生表》中的辅导员编号,和《辅导员表》中的辅导员编号是一一对应的
说明3:这种情况下就可以通过辅导员编号这个字段将《学生表》和《辅导员表》联系起来了
说明4:这是辅导员编号字段,就符合设置为外键的条件
说明5:如果将《学生表》中的辅导员编号字段设置为外键,则《学生表》为子表,《辅导员表》为父表
说明6:外键在父表中是唯一,不可重复的。
说明1:通过上图发现《学生表》中的班级id和《班级表》中的班级id也存在一一对应的关系
说明2:班级id也符合设置外键的标准。
说明3:例如:辅导员编号,班级id都符合外键的设置标准,所以一个表中可以有多个外键,但是每个外键对应不同的表
说明1:在《学生表》班级评级字段和《班级考核与平级对照表》中的班级平级字段也存在着关系。
说明2:但是这个班级评级字段就不存在外键的特征,因为班级评级在《班级考核与评级对照表》中不是惟一的。
说明3:在子表中的四星,对应父表中有三种情况这样就会出现子表中的四星到底对应父表的哪一个四星的情况。
1、原始数据:student表结构及其数据
mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | 1 | 98 | | 2 | stu2 | 1 | 88 | | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.00 sec)
2、原始数据:teacher表结构及其数据
mysql> select * from teacher; +------------+--------------+ | id | teacher_name | +------------+--------------+ | 1 | 张三 | | 2 | 李四 | | 3 | 王五 | +------------+--------------+ 3 rows in set (0.00 sec)
3、添加外键的语法
alter table 表名 add constraint 外键名称 foreign key (外键字段名) references 父表 (父表字段)on update 更新行为 on delete 删除行为
说明1:alter table 是DML语法,修改表的意思,在之前的文章中已经介绍过
说明2:add constraint 是添加约束的意思
说明3:foreign key 是外键约束的关键字
说明4:references 后面跟上父表和父表中字段
4、需求:给student表中的teacher_id设置为teacher表的外键,并且对应id字段的数据
mysql> alter table student add constraint fk_teacher foreign key (teacher_id) references teacher (id); Query OK, 6 rows affected (0.22 sec) Records: 6 Duplicates: 0 Warnings: 0
说明1:外键一旦设置成功,将会保持子表和父表的数据一致性和完整性。
说明2:这个时候,如果我删除《teacher》表中的id=1的张三老师,就会出错,因为,如果张三在《teacher》表中删除了,则在《student》中的辅导员编号这列数据就找不到对应的值
说明3:从而这样就破坏了数据的完整性和一致性
mysql> delete from teacher where id=1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`mysql_test`.`student`, CONSTRAINT `fk_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`))
说明1:这个时候就会提示,不能删除或者修改父表中的数据,因为有外键存在
5、外键数据的更新和删除行为
6、重新创建《student》和《teacher》表并添加外键
mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | 1 | 98 | | 2 | stu2 | 1 | 88 | | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.00 sec) mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 1 | 张三 | | 2 | 李四 | | 3 | 王五 | +----+--------------+ 3 rows in set (0.00 sec) mysql> alter table student add constraint fk_teacher foreign key (teacher_id) references teacher(id) on update cascade on delete cascade; Query OK, 6 rows affected (0.05 sec) Records: 6 Duplicates: 0 Warnings: 0
7、验证cascade级联行为
验证1:我修改《teacher》表中id=1的数据改为id=4
mysql> update teacher set id=4 where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 2 | 李四 | | 3 | 王五 | | 4 | 张三 | +----+--------------+ 3 rows in set (0.01 sec) mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | 4 | 98 | | 2 | stu2 | 4 | 88 | | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.00 sec)
说明1:这个时候我们会发现,当我修改了《teacher》表中辅导员编号的id字段是,在《student》表中teacher_id 原本等于1的也都改为了4,这就是cascade的作用
验证2:cascade的删除行为
mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 2 | 李四 | | 3 | 王五 | +----+--------------+ 2 rows in set (0.00 sec) mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 4 rows in set (0.00 sec)
说明2:和更新一样,cascade的删除也是级联的。
8、验证set null的更新和删除行为
需求1:同样先删除《student》和《teacher》表然后重新建立新的表,重新建立外键约束测试
mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 1 | 张三 | | 2 | 李四 | | 3 | 王五 | +----+--------------+ 3 rows in set (0.00 sec) mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | 1 | 98 | | 2 | stu2 | 1 | 88 | | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.00 sec) mysql> alter table student add constraint fk_teacher foreign key (teacher_id) references teacher(id) on update set null on delete set null; Query OK, 6 rows affected (0.04 sec) Records: 6 Duplicates: 0 Warnings: 0
验证1:更新《teacher》表中id=1的数据,改为id=4
mysql> update teacher set id=4 where id=1; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 2 | 李四 | | 3 | 王五 | | 4 | 张三 | +----+--------------+ 3 rows in set (0.00 sec) mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | NULL | 98 | | 2 | stu2 | NULL | 88 | | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.01 sec)
说明1:对应更新的数据都改为了null
验证2:删除《teacher》表中id=2的数据
mysql> delete from teacher where id = 2; Query OK, 1 row affected (0.01 sec) mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 3 | 王五 | | 4 | 张三 | +----+--------------+ 2 rows in set (0.00 sec) mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | NULL | 98 | | 2 | stu2 | NULL | 88 | | 3 | stu3 | NULL | 79 | | 4 | stu4 | NULL | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.00 sec)
说明1:当删除数据的时候,子表中对应的外键数据也会变成了null
1、删除外键的语法
alter table 表名 drop foreign key 外键名称;
mysql> alter table student drop foreign key fk_teacher; Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0
2、删除外键后,数据一致性和完整性的验证
mysql> delete from teacher where id=1; Query OK, 1 row affected (0.01 sec) mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 2 | 李四 | | 3 | 王五 | +----+--------------+ 2 rows in set (0.00 sec)
说明1:这个时候就可以在《teacher》表中删除id=1的张三老师了,但是这样《student》表和《teacher》表的数据的一致性就破坏了