十三、约束(★★★★★)
13.1 什么是约束
约束对应的英语单词:constraint
在创建表的时候,我们可以给表中的字段加上一些约束来保证这个表中数据的完整性、有效性!
约束的作用:保证表中的数据有效!
13.2 约束包括哪些
- 非空约束:not nll
- 唯一性约束:unique
- 主键约束:primary key(简称PK)
- 外键约束:foregin key(简称FK)
- 检查约束:check(mysql不支持,oracle支持)
13.3 非空约束–not null
非空约束not null 约束的字段不能为NULL
mysql> drop table if exists t_vip;
Query OK, 0 rows affected (0.01 sec)
mysql> create table t_vip(
-> id int,
-> name varchar(255) not null
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> desc t_vip;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(255) | NO | | NULL | |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> insert into t_vip(id, name) values(1, 'zhangsan');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_vip(id, name) values(2, 'lisi');
Query OK, 1 row affected (0.00 sec)
# 注意这里
mysql> insert into t_vip(id) values(3);
ERROR 1364 (HY000): Field 'name' doesn't have a default value
拓展:
xxxx.sql 这种文件被称为 sql脚本文件。sql脚本文件中编写了大量的sql语句。
我们执行sql脚本文件的时候,该文件中所有的sql语句会全部执行!批量的执行SQL语句时,可以使用sql脚本文件。
在mysql中如何执行sql脚本?------>
mysql> source H:\vip.sql
当你执行完这个脚本文件后,你电脑上的数据库数据就有了!
13.4 唯一性约束–unique
唯一性约束unique 约束的字段不能重复,但是可以为NULL。
-
约束直接添加到列后面的,叫做列级约束
-
约束没有添加在列的后面,被称为表级约束
什么时候使用表级约束?
需要给多个字段联合起来添加某一个约束的时候,需要使用表级约束。
mysql> drop table if exists t_vip;
Query OK, 0 rows affected (0.01 sec)
mysql> create table t_vip(
-> id int,
-> name varchar(255) unique, # name字段唯一性约束
-> email varchar(255)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t_vip(id, name, email) values(1, 'zhangsn', '[email protected]');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_vip(id, name, email) values(2, 'lili', '[email protected]');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t_vip;
+------+---------+----------------+
| id | name | email |
+------+---------+----------------+
| 1 | zhangsn | zhangsn@11.com |
| 2 | lili | lili@11.com |
+------+---------+----------------+
2 rows in set (0.00 sec)
# 这里name重复了,会报错
mysql> insert into t_vip(id, name, email) values(3, 'lili', '[email protected]');
ERROR 1062 (23000): Duplicate entry 'lili' for key 'name'
mysql> insert into t_vip(id) values(3);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_vip(id) values(4);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t_vip;
+------+---------+----------------+
| id | name | email |
+------+---------+----------------+
| 1 | zhangsn | zhangsn@11.com |
| 2 | lili | lili@11.com |
| 3 | NULL | NULL |
| 4 | NULL | NULL |
+------+---------+----------------+
4 rows in set (0.00 sec)
下面要求name 和 email两个字段联合起来具有唯一性!
先看一个错误示例:
mysql> drop table if exists t_vip;
Query OK, 0 rows affected (0.01 sec)
mysql> create table t_vip(
-> id int,
-> name varchar(255) unique, # 约束直接添加在列后面的,叫做列级约束
-> email varchar(255) unique
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into t_vip(id,name,email) values(1,'zhangsan','[email protected]');
Query OK, 1 row affected (0.00 sec)
# 下面会报错
mysql> insert into t_vip(id,name,email) values(2,'zhangsan','[email protected]');
ERROR 1062 (23000): Duplicate entry 'zhangsan' for key 'name'
这样创建表示:name具有唯一性,email具有唯一性。各自唯一。
怎样创建这样的表,才能符合新需求呢?
mysql> drop table if exists t_vip;
Query OK, 0 rows affected (0.00 sec)
mysql> create table t_vip(
-> id int,
-> name varchar(255),
-> email varchar(255),
-> unique(name,email) # 注意这一句,约束没有添加在列的后面,这种约束被称为表级约束
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t_vip(id,name,email) values(1,'zhangsan','[email protected]');
Query OK, 1 row affected (0.00 sec)
# 并没有报错
mysql> insert into t_vip(id,name,email) values(2,'zhangsan','[email protected]');
Query OK, 1 row affected (0.00 sec)
# 这样会报错---联合唯一
mysql> insert into t_vip(id,name,email) values(3,'zhangsan','[email protected]');
ERROR 1062 (23000): Duplicate entry '[email protected]' for key 'name'
mysql> select * from t_vip;
+------+----------+-------------------+
| id | name | email |
+------+----------+-------------------+
| 1 | zhangsan | zhangsan@123.com |
| 2 | zhangsan | zhangsan@sina.com |
+------+----------+-------------------+
2 rows in set (0.00 sec)
上面的示例,实现了name和email两个字段联合起来唯一。
13.5 unique和not null可以联合吗
mysql> drop table if exists t_vip;
Query OK, 0 rows affected (0.00 sec)
mysql> create table t_vip(
-> id int,
-> name varchar(255) not null unique # 联合起来
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> desc t_vip;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(255) | NO | PRI | NULL | |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
可以看到,在mysql中,如果一个字段同时被not null和unique约束的话,该字段自动变成主键约束(注意!oracle中不一样!)
mysql> insert into t_vip(id,name) values(1,'zhangsan');
Query OK, 1 row affected (0.00 sec)
# ERROR:name不能重复
mysql> insert into t_vip(id,name) values(2,'zhangsan');
ERROR 1062 (23000): Duplicate entry 'zhangsan' for key 'name'
# ERROR:name不能为NULL
mysql> insert into t_vip(id) values(2);
ERROR 1364 (HY000): Field 'name' doesn't have a default value
13.6 主键约束–primary key(★★★★★)
13.6.1 相关术语
- 主键约束:就是一种约束
- 主键字段:该字段上添加了主键约束,这样的字段被称为 主键字段
- 主键值:主键字段中的每一个值都叫做 主键值
13.6.2 什么是主键?有嘛子用
- 主键值是每一行记录的唯一标识
- 主键值是每一行记录的身份证号!
任何一张表都应该有主键,没有主键,表是无效的!
主键的特征:not null + unique
(主键值不能是NULL,同时也不能重复!)
13.6.3 怎么给一张表添加主键约束呢?
mysql> drop table if exists t_vip;
Query OK, 0 rows affected, 1 warning (0.00 sec)
# 一个字段做主键,叫做单一主键
mysql> create table t_vip(
-> id int primary key, # 添加主键
-> name varchar(255)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t_vip(id, name) values(1, 'zhangsan');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_vip(id, name) values(2, 'list');
Query OK, 1 row affected (0.00 sec)
# 错误,id不能重复
mysql> insert into t_vip(id, name) values(2, 'wangwa');
ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
# 错误:id不能为NULL
mysql> insert into t_vip(name) values('zhangs');
ERROR 1364 (HY000): Field 'id' doesn't have a default value
可以这样添加主键吗?
mysql> drop table if exists t_vip;
Query OK, 0 rows affected (0.01 sec)
mysql> create table t_vip(
-> id int,
-> name varchar(255),
-> primary key(id) # 看这里,表级约束
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t_vip(id,name) values(1,'zhangsan');
Query OK, 1 row affected (0.00 sec)
# ERROR
mysql> insert into t_vip(id,name) values(1,'lisi');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
13.6.4 表级约束主要是给多个字段联合起来添加约束的吗?
mysql> drop table if exists t_vip;
Query OK, 0 rows affected (0.00 sec)
mysql> create table t_vip(
-> id int,
-> name varchar(255),
-> email varchar(255),
-> primary key(id, name) # id和name联合起来做主键,叫做复合主键!
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t_vip(id,name,email) values(1,'zhangsan','[email protected]');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_vip(id,name,email) values(1,'lisi','[email protected]');
Query OK, 1 row affected (0.00 sec)
# ERROR
mysql> insert into t_vip(id,name,email) values(1,'lisi','[email protected]');
ERROR 1062 (23000): Duplicate entry '1-lisi' for key 'PRIMARY
在实际开发中,不建议使用 复合主键。建议使用单一主键!
因为主键值存在的意义就是这行记录的身份证号,只要意义达到即可,单一主键就可以做到。
复合主键比较复杂,不建议使用!!!
13.6.5 一个表中主键约束能加两个吗?
mysql> create table t_vip(
-> id int primary key,
-> name varchar(255) primary key
-> );
ERROR 1068 (42000): Multiple primary key defined
结论:一张表,主键约束只能添加1个(主键只能有1个,当然可以有复合主键)
13.6.6 auto_increment机制
在mysql中,auto_increment 机制可以帮助我们自动维护一个主键值:
mysql> drop table if exists t_vip;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> create table t_vip(
-> id int primary key auto_increment, # auto_increment表示自增,从1开始,以1递增!
-> name varchar(255)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t_vip(name) values('zhangsan');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_vip(name) values('zhangsan');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_vip(name) values('zhangsan');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_vip(name) values('zhangsan');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_vip(name) values('zhangsan');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t_vip;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
| 2 | zhangsan |
| 3 | zhangsan |
| 4 | zhangsan |
| 5 | zhangsan |
+----+----------+
5 rows in set (0.00 sec)
13.6.7 建议
主键值建议使用:
- int、bigint、char等类型
不建议使用
varchar
来做主键。主键值一般都是数字------一般都是定长的。
主键除了:单一主键 和 复合主键,还可以这样分类:
- 自然主键:主键值是一个自然数,和业务没关系
- 业务主键:主键值和业务紧密关联
例如:拿银行卡账号做主键值,这就是业务主键!在实际开发中,自然主键使用比较多,因为主键只要做到不重复就行,不需要有意义。业务主键不好,因为主键一旦和业务挂钩,那么当业务发生变动的时候,可能会影响到主键值,所以业务主键不建议使用。
13.7 外键约束–foreign key(★★★★★)
外键约束相关术语:
- 外键约束:一种约束
- 外键字段:添加了外键约束的字段
- 外键值:外键字段当中的每一个值
业务背景:
请设计数据库表,来描述“班级和学生”的信息?
第一种方案:班级和学生存储在一张表中:
t_student
no(pk) name classno classname
----------------------------------------------------------------------------------
1 jack 100 北京市大兴区亦庄镇第二中学高三1班
2 lucy 100 北京市大兴区亦庄镇第二中学高三1班
3 lilei 100 北京市大兴区亦庄镇第二中学高三1班
4 hanmeimei 100 北京市大兴区亦庄镇第二中学高三1班
5 zhangsan 101 北京市大兴区亦庄镇第二中学高三2班
6 lisi 101 北京市大兴区亦庄镇第二中学高三2班
7 wangwu 101 北京市大兴区亦庄镇第二中学高三2班
8 zhaoliu 101 北京市大兴区亦庄镇第二中学高三2班
方案缺点:
- 数据冗余,空间浪费
第二种方案:班级一张表、学生一张表:
t_class 班级表
classno(pk) classname
------------------------------------------------------
100 北京市大兴区亦庄镇第二中学高三1班
101 北京市大兴区亦庄镇第二中学高三1班
t_student 学生表
no(pk) name cno(FK引用t_class这张表的classno)
----------------------------------------------------------------
1 jack 100
2 lucy 100
3 lilei 100
4 hanmeimei 100
5 zhangsan 101
6 lisi 101
7 wangwu 101
8 zhaoliu 101
注意:t_class是父表,t_student是子表
删除表的顺序 ===》 先删子,再删父
创建表的顺序 ===》 先创建父,再创建子
删除数据的顺序 ===》 先删子,再删父
插入数据的顺序 ===》 先插入父,再插入子
当cno字段没有任何约束的时候,可能会导致数据无效。如可能出现一个102班级,但是102班级并不存在,所以为了保证cno字段中的值都是100和101,需要给cno字段添加外键约束 。
===》cno字段就是外键字段,cno字段中的每个值都是外键值
思考:子表中的外键引用的父表中某个字段,被引用的这个字段必须是主键吗?
===》不一定是主键,但至少具有unique约束
测试:外键可以为NULL吗?
===》外键值可以是NULL