数据库设计三范式
范式可以避免数据冗余,减少数据库的空间,减轻维护数据完整性的麻烦,但是操作困难,因为需要联系多个表才能得到所需要数据,而
且范式越高性能就会越差。要权衡是否使用更高范式是比较麻烦的,一般在项目中,用得最多的也就是第三范式,个人认为使用到第三范式
也就足够了,性能好而且方便管理数据。
第一范式
定义:如果关系模式R的每个关系r的属性都是不可分的数据项,那么就称R是第一范式的模式。
简单的说,数据库表中的所有字段值都是不可分解的原子值,不可再分割,并且有意义。
错误示例:创建一个学生表
create table person(
id varchar(18) primary key,
name varchar(20) not null,
info varchar(200)
);
insert into person(id,name,info)
values("321645987945645","张三","出生日期:1980-1-1 家庭住址:中国陕西西安雁塔区电子称西部电子社区");
在这个学生表中,info字段包含太多的内容,info字段可以分割为以下信息:
生日、国籍、籍贯、城市、区域、详细地址
创建正确的person表应该如下:
create table person(
id varchar(18) primary key,
name varchar(20) not null,
birthday date,
guoji varchar(20),
jiguan varchar(20),
city varchar(20),
area varchar(20),
address varchar(50)
);
第二范式
定义:如果关系模式R是1NF,且每个非主属性完全函数依赖于候选键,那么就称R是第二范式。
简单的说,第二范式要满足以下的条件:首先要满足第一范式,其次每个非主属性要完全函数依赖与候选键,或者是主键。也就是说,
每个非主属性是由整个主键函数决定的,而不能由主键的一部分来决定。即,必须存在主键且唯一
也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
如果所有情况都按第一范式设计就会有很多问题,例如:有一个学生成绩表,包含学号、姓名、课程、成绩
create table student(
id int primary key,
name varchar(20),
course varchar(20),
grade int
)
insert into student(id,name,course,grade) values(1001,"张三","Java",80);
insert into student(id,name,course,grade) values(1002,"张四","Java",80);
insert into student(id,name,course,grade) values(1003,"张五","C",80);
insert into student(id,name,course,grade) values(1004,"张六","c++",80);
以上表的设计会造成以下问题:
1、课程信息重复,一般会课程设置编号,但是编号在这里会重复出现。
2、如果有一个课程没有学生选修,这个课程的信息就不存在了。
3、修改课程信息时需要修改多条数据。
使用第二范式修改如下:
create table student(
id int primary key,
name varchar(20)
)
课程表作为一个实体表
create table course(
id int primary key,
name varchar(20)
)
选课表用来描述学生实体与课程实体之间的关系
create table sc(
sid int,
cid int,
grade int
)
这里其实是一个多对多的关系,一个学生可以选择多门课程,一个课程可以被多个学生选修
课程信息不会重复,课程编号也是唯一的
即使没有学生选择的课程信息也不会丢失
修改课程信息时只需要修改一条信息即可
第三范式
实际我使用第三范式最多。
定义:如果关系模式R是2NF,且关系模式R(U,F)中的所有非主属性对任何候选关键字都不存在传递依赖,则称关系R是属于第三范式。
简单的说,第三范式要满足以下的条件:首先要满足第二范式,其次非主属性之间不存在函数依赖。由于满足了第二范式,表示每个
非主属性都函数依赖于主键。如果非主属性之间存在了函数依赖,就会存在传递依赖,这样就不满足第三范式。
即,非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
例如:学生表包含信息学号、姓名、所在学校、学校地址、学校电话
create table student(
id int,
name varchar(20)
)
create table school(
id int,
name varchar(20),
address varchar(30),
tel varchar(50)
)
create table ss(
sid int,
scid int
)
上边的例子则是描述的多对多的关系,这时一个学生可以在多个学校上学,一个学校有多个学生。
第三范式描述的是一个一对多的关系:
create table student(
id int,
name varchar(20),
scid int
)
create table school(
id int,
name varchar(20),
address varchar(30),
tel varchar(50)
)