硅基计划5.0 MySQL 贰 SQL约束三大范式
文章目录
- 1. 数据库约束
- 1. 列不为空值——not null
- 2. 列的默认值——default
- 3. 指定列的值不能重复——unique
- 4. 主键约束——primary key
- 5. 外键约束——foreign key
- 6. 自定义约束——check
- 2、三大范式
- 1. 第一范式
- 2. 第二范式
- 3. 第三范式
- 4. 总结
1. 数据库约束
我们在创建数据库后,在里面创建表,我们可以针对表的特定行特点列指出特定的格式要求
我们就沿用上一篇文章中的数据库来做演示
1. 列不为空值——not null
insert into tmp_information values(null,'张三');
2. 列的默认值——default
create table tmp_information(id int default 0,name varchar(10));insert into tmp_information(name) values('张三');select * from tmp_information;
3. 指定列的值不能重复——unique
create table tmp_information(id int unique,name varchar(20));insert into tmp_information values(1,'张三');insert into tmp_information values(1,'李四');insert into tmp_information values(null,'王五');
但是对于Null值是允许重复的
4. 主键约束——primary key
这个相当于unique
+not null
的结合体
create table tmp_information(id int primary key,name varchar(10));insert into tmp_information values(null,'张三');insert into tmp_information values(null,'李四');insert into tmp_information values(1,'王五');insert into tmp_information values(1,'赵六');select * from tmp_information;
可以看到结果的表中并没有Null的值而且也没有重复值
当然,我们也可以使用自增主键,说白了就是当值重复后,自动分配合适的主键
create table tmp_information(id int primary key auto_increment,name varchar(10));insert into tmp_information values(10,'张三');insert into tmp_information values(null,'李四');insert into tmp_information values(100,'王五');insert into tmp_information values(null,'赵六');
可以看到自增主键会根据插入的数据自动分配合理的主键
当我们创建id = 10
后,插入新的数据会分配到11
但一旦当我们插入id = 100
后,再插入新的数据则会往后分配了
因此如果使用自增主键可能会造成空间浪费,但也没关系
5. 外键约束——foreign key
这个约束主要是对于两张表之间的某种联系,比如我这里有两张表,一张表是学生信息表,一张是班级信息表
那么这两个表之间,我们可以通过班级id去确认其具体班级
但是你是否有发现赵六的班级是四班,可是我班级信息表中不存在四班啊,因此我们可以认为赵六四班这条数据是一个无效数据
虽然还是可以正常插入,但是不符合实际要求啊,那么怎么让数据库知道这是一条无效数据呢
这就是我们要讲的外键约束
那么,接下来,我们来实现代码
use home;create table class(class_id int primary key auto_increment,class_name varchar(3));insert into class values(1,'一班'),(2,'二班'),(3,'三班');create table student(name varchar(10),class_id int,age int,foreign key(class_id) references class(class_id));insert into student values('张三',1,18),('李四',2,19),('王五',3,20);insert into student values('赵六',4,19);
可以看到报错信息提示我们插入的4班并未在班级表中存在,即外键约束
同理,我们想修改各个学生的班级信息,那么我们修改的班级必须在班级信息表中存在才可以
同理,如果在学生信息表中删除的班级是在班级信息表中已经存在的,也不可以
因此,说白了就是两个表之间存在相互约束关系
接下来看这一种情况
之前我在写班级信息表的时候,对于班级id那一列,我是使用了主键的,但是这一次我没有使用主键,当我使用外键约束创建学生信息表的时候,对于班级id那一列,报错了
为什么会报错,这是因为我们数据在进行全列查询的时候,加入数据表的数据非常之庞大,逐行遍历是非常耗时耗资源的,因此我们在查询的时候通常会用到索引
而这个索引,就是我们使用主键的时候创建的
我们没有使用主键约束某个特定列,就会导致我们在查询的时候非常不便
因此MYSQL要求使用外键约束的前提必须是约束来源的那个表的约束列必须使用主键
其实不一定是primary key
才可以,unqiue
约束也可以
接下来再看一种极端情况
就接着我们刚刚那两张表,如果发生这样的情况:三班因为人数过少被撤销了
这个时候你难道想把是三班的同学的信息删去吗?但是因为你使用了外键约束,导致我们无法删除
这时候我们就可以这样,我们在班级后面再添加一列,表示班级状态,可以使用布尔值或者是0与1方式表示
一旦这个班级撤销了,我们在其后面的列标记,这样当其他人查看的时候,就会提示这个班级被撤销了
虽然提示是被撤销,但实际上还是在硬盘上,只是换了一种显示方式而已
6. 自定义约束——check
这个约束在实际开发中非常常用,能过大大提高自定义的空间
比如我想让一张价格表中商品价格不能超过100元或者是商品类型只能是饮料和零食
create table food_shop(name varchar(20),type varchar(5),price decimal(5,2),check(price > 0.00 and price <= 100.00),check(type = '零食' or type = '饮料'));insert into food_shop values('冰红茶','饮料',4.00),('QQ糖','零食',1.00);
你看,在下面两张图片中,不管是种类还是价格,如果不在符合的约束范围内,就无法插入
2、三大范式
我们在设计数据库的时候,要怎么设计才合规范,这就是我们要讲的三大范式
1. 第一范式
定义:每一列要为不可分割的原子数据项
说人说就是每一列能不可再拆分,每一列都是最小的数据单位
比如在学生信息表中的学校信息,如果你只填一个学校,那么我们是不是还是不知道这个学生具体在哪
因此学校那一列具体可以拆分成学院,学院所在校区,学院电话等等
2. 第二范式
定义:在第一范式基础上,当表中定义复合主键时候,不存在非关键字段对任意候选键的部分函数依赖
我们先来解释相关概念
- 复合主键:我们平常都是指定一个主键。但是在复合主键中,我们是指定多个主键与之对应
比如在成绩表中我们通过学号+科目确定一位学生某个科目考试成绩 - 候选键:刚刚提到复合主键是由多个列指定的,因此其中的某一个列就叫做候选键
这里提个醒,对于复合主键,只有把几个列合在一起了我们才叫做这个表的主键,单拎出来一列我们就叫做候选键 - 非关键字段:主键以外的列
- 函数依赖:通过整个主键确定一条数据,就比如我们刚刚的学号+科目确定一位学生某个科目考试成绩
- 部分函数依赖:意思是我们不用通过整个主键去确定一条数据,而是主键的任意一部分去确定
比如还是在成绩那一列,我们成绩表中包含姓名,那么我确定一位学生姓名,我是不是只需要通过学号确定就好,跟科目没关系啊,这就是部分函数依赖
这么说难免干巴,我直接拿一张表来演示
那么如何去解决这个问题呢,很简单,我们一般都是每个表指定一个主键
好,那么我们可以把一个表拆分成几个表去表示
我直接把拆分结果给大家看
3. 第三范式
定义:在第二范式基础上,不存在非关键字段的传递依赖
我们先来说说什么是传递依赖,比如这张表
很明显,这张表是不合格的,除了在不当场景使用符合主键外,还存在传递依赖,怎么个传递法?
通过学号-->
确定这名学生所在的学院,再通过学院-->
确定所在校区和学院电话
你看,这三者之间,除了学院和学号是主键,学院校区和学院电话都是普通列
这就形成了非关键字段的传递依赖
因此,和我们刚刚那个表一样,拆分,让每一个表只能有一个主键,并且是一对一关系,不能形成传递依赖
4. 总结
我们在构造数据表的时候,要保证每一列不可拆分,并且一个标只能有一个主键,并且不能形成非关键字段的传递依赖
因此我们的每一张表只能有一个核心内容(主键),其他列都是围绕着这个核心内容展开的