Design4:数据库设计规范
当数据模型从概念层转到逻辑层时,需要进行规范化设计。要想设计一个结构合理的关系型数据库,至少需要满足1NF,2NF,3NF,即第一范式,第二范式,第三范式。
1,1NF(原子性)
1NF是最基本的,数据库表的每一列都是不可分割的原子数据项。
不可分割是相对而言的,依据实际需求来界定。
严格的说,某些TSQL的系统数据类型违反1NF,例如DateTime类型,包含了year,month,day,hour,minute,second,millisecond,但是我们更希望这些属性组合在一起,标识事情发生的具体时间点。
1NF提供了一种规范,优秀的设计模型,例如 姓名(full name)包含两部分,姓氏和名字,如果应用程序不会分别获取姓氏或名字,可以将full name视为原子数据项,但是,如果程序需要获取姓氏或名字,那么将full name拆分,划分为两列(surname 和 name)是更好的设计模型。
2,2NF(属性完全依赖于主键)
表中的所有列,都必须完全依赖于主键,由主键唯一标识所有属性列,对于不完全依赖于主键的列,会出现数据冗余,需要拆分成表。
例如以下是个成绩表,各个字段的含义是 Cid(course id),Cname(course name),stuid(student id),stuname(student name),主键是cid和stuid,但是cname,stuname,professionid和professionname并不完全依赖于主键,cname完全依赖于CID,stuname,professionid和professionname完全依赖于stuid。
按照2NF的要求,将依赖于主键属性的所有属性集中到一个表中,上图数据能拆分成三个表,dbo.student,dbo.course,dbo.score,消除数据的冗余。
表是属性的集合,一个表是一个实体,例如student表,有学号,name,profession属性,学号是主键属性,能唯一标识一个student实体,能够根据学号唯一确定一位学生的name,profession属性。
create table dbo.student ( stuid int not null primary key, stuname varchar(100) not null, professionid int , professionname varchar(100) ) create table dbo.course ( cid int not null primary key, cname varchar(100) not null ) create table dbo.score ( cid int not null foreign key references dbo.course(cid), stuid int not null foreign key references dbo.student(stuid), score int null primary key(cid,stuid) )
3,3NF(属性不能传递依赖于主属性,即属性不依赖于其它非主键属性)
如果某一属性A依赖于非主键属性B,而非主键属性B依赖于主键pk,那么属性A就是间接依赖于主键pk,这被称作传递依赖于主属性。
例如,ProfessioName 是专业名称,每一个专业的名称是唯一的,跟学生没有关系,ProfessioName依赖于ProfessionID,而ProfessionID完全依赖于stuid,因为student表的属性是由stuid唯一标识的,所以ProfessioName传递依赖于stuid。
对传递依赖进行范化,需要将传递依赖的属性拆分成表,例如
create table dbo.profession ( professionid int not null primary key, professionname varchar(100) ) create table dbo.student ( stuid int not null primary key, stuname varchar(100) not null, professionid int foreign key references dbo.profession(professionid) )