提示:以下是本篇文章正文内容,下面案例可供参考
数据库范式分为第一范式(1NF),第二范式(2NF),第三范式(3NF)
一、第一范式
是对属性的原子性,要求属性具有原子性,不可再分解 什么是原子性?在化学上讲原子是不可再分的
举个例子:
use test
create table Student
(
StudId varchar(20) primary key,
StuName varchar(20) not null,
StuContact varchar(50) not null,
)
insert into Student(StudId,StuName,StuContact)
values(1,'张三','QQ:12345,Tel:138********')
select * from Student
如果哪天我想根据QQ来查找人怎么办?你联系方式里可不止QQ一个信息啊,就非常麻烦了。
所以根据第一范式的原子性,我们将代码修改一下——把联系方式拆分成联系电话和联系QQ
create table Student
(
StudId varchar(20) primary key,
StuName varchar(20) not null,
Tel varchar(50) not null,
QQ varchar(20) not null
)
这样子,将来如果需要对联系QQ进行查找人,就很方便了。
二、第二范式
是对记录的唯一性,要求记录有唯一标识,也就是实体的唯一性,即不存在部分依赖。 什么叫作实体的唯一性? 比如我们这里创建的学生表,就有实体的唯一性:
create table Student
(
StudId varchar(20) primary key,
StuName varchar(20) not null,
Tel varchar(50) not null,
QQ varchar(20) not null
)
insert into Student(StudId,StuName,Tel,QQ)
values(1,'张三','Tel:138********','QQ:12345')
select * from Student
我们查找到的信息,一个StuId可以唯一标识一行,是可以代表一个学生的, 如果到了第二行,又会是另一个学生,这就是唯一性
那什么时候我们实体的唯一性会被打破? 比如下面的代码:
create table StudentCourse
(
StuId varchar(20),
StuName varchar(20) not null,
CourseId varchar(20) not null,
CourseName varchar(20) not null,
CourseScore int not null
)
insert into StudentCourse(StuId,StuName,CourseId,CourseName,CourseScore)
values('1','张三','01','语文',90)
insert into StudentCourse(StuId,StuName,CourseId,CourseName,CourseScore)
values('1','张三','02','数学',87)
insert into StudentCourse(StuId,StuName,CourseId,CourseName,CourseScore)
values('2','李四','03','英语',91)
insert into StudentCourse(StuId,StuName,CourseId,CourseName,CourseScore)
values('3','王五','03','英语',95)
select * from StudentCourse
我们看看:一人选了两门课,和一门课被两个人选了是什么效果 在第一行出现了“张三”,第二行又出现了“张三”,这并没有保证学生的唯一性 另外,图中三四行的英语,也出来了两次,也是没有保证课程的唯一性。 没有保证唯一性就会出现数据上的冗余。比如张三,你明明可以把他选的语文和数学放一起,你却没有这么做,你让张三这条信息多出现了一次,这就是冗余。
上述设计中有两个事物,一个学生信息,一个课程信息,很显然这两个事物都没有保证实体的唯一性,这里的姓名依赖学号,课程名依赖课程编号,所以不符合二范式。,你不符合第二范式就会出现一系列的问题, 问题1:你英语可能有很多人选吧,这些人中又很有可能选了别的课,你这样一个课一个课,那个人名的信息就很冗余了,一个人对应那么多信息。 问题2:对数据的维护(比如增删查改),比如我现在增加一个学生,因为现在这个表既保存学生信息也保存课程信息,如果我现在有一个学生信息要添加,但是他还没有选课,你怎么加?我现在课程那些又是not null不能为空的,怎么办?
所以我们上面很粗暴的用一张表把信息存储起来很不规范,不符合第二范式,我们来改进一下代码:
create table Course(
CourseId int primary key identity(1,1),
CourseName varchar(30) not null,
CourseContent text
)
insert into Course(CourseName,CourseContent) values('HTML','静态网页制作')
insert into Course(CourseName,CourseContent) values('winForm','Windows应用程序开发')
create table Student(
StuId int primary key identity,
StuName varchar(50) not null,
StuSex char(2) not null
)
insert into Student(StuName,StuSex) values('张三','男')
insert into Student(StuName,StuSex) values('李四','女')
create Table Exam(
ExamId int primary key identity(1,1),
StuId int not null,
CourseId int not null,
Score int not null
)
insert into Exam(StuId,CourseId,Score) values(1,1,90)
insert into Exam(StuId,CourseId,Score) values(1,2,80)
insert into Exam(StuId,CourseId,Score) values(2,1,95)
insert into Exam(StuId,CourseId,Score) values(2,2,90)
select * from Course
select * from Student
select * from Exam
按照上面的代码进行建表就不会出现数据的冗余,同样的数据不会出现多次了 并且这种优化方案,对于数据的维护,比如你要修改课程信息,你只要维护Course表即可
唯一麻烦的就是查询,比如我要找张三考了多少分,现在数据少好像你在 Exam表里面找找也能出来,但是数据多就比较麻烦,所以是建议用连接查询。
select * from Student
inner join Exam on Student.StuId=Exam.StuId
inner join Course on Course.CourseId=Exam.CourseId
三、第三范式
在2NF的基础上,任何的非主属性不依赖于其他非主属性 (在第二范式基础上消除传递依赖)
举个例子
create table Student(
StuId varchar(10) primary key ,
StuName varchar(50) not null,
ProfessionName varchar(50),
ProfessionRemark varchar(20)
)
insert into Student(StuId,StuName,ProfessionName,ProfessionRemark)
values('1','张三','计算机科学与技术','牛逼牛逼')
insert into Student(StuId,StuName,ProfessionName,ProfessionRemark)
values('2','李四','软件工程','也很牛逼')
insert into Student(StuId,StuName,ProfessionName,ProfessionRemark)
values('3','王五','计算机科学与技术','牛逼牛逼')
select * from Student
上面创建的学生表中,学生编号和学生姓名是直接依赖关系的,但是学生编号和专业介绍却是间接依赖的,什么意思?就是你可以通过学生编号找到他的专业名称,也就是学生编号和专业名称直接依赖。 然后通过专业名称确定专业介绍,专业名称和专业介绍直接依赖。 这种z=f(y),y=f(x),即z依赖y,y依赖x。就可以说z间接依赖x 第三范式要求没有这种间接依赖
我们再来看这种不符合第三范式表的缺陷是什么? 现在是数据少的情况。假设计算机科学与技术有1000名学生,然后专业描述有1000字,你这1000*1000得有多少冗余数据啊(同样专业描述只需要有一个就行了)。
改进方法:和第二范式改进一样——拆表
create table Professional(
ProfessionalId int primary key identity(1,1),
ProfessionalName varchar(50),
ProfessionalRemark varchar(200)
)
create table Student(
StuId varchar(10) primary key ,
StuName varchar(50) not null,
ProfessionName varchar(50),
)
insert into Professional(ProfessionalName,ProfessionalRemark) values('计算机科学与技术','小母牛蒸桑拿')
insert into Professional(ProfessionalName,ProfessionalRemark) values('软件工程','小母牛抽大烟')
insert into Student(StuId,StuName,ProfessionName)
values('1','张三','计算机科学与技术')
insert into Student(StuId,StuName,ProfessionName)
values('2','李四','软件工程')
insert into Student(StuId,StuName,ProfessionName)
values('3','王五','计算机科学与技术')
select * from Professional
select * from Student
这样看,之前的数据冗余就消失了
|