数据库设计将会表示为一个
关系数据库设计
和一个与之关联的约束集合
。
1. 设计过程概览
1.1 设计阶段
构建一个数据库应用包括有设计数据库模式
,设计访问和更新数据的程序
以及设计控制数据访问的安全模式
。
一个高层的数据模型为数据库设计者提供了一个概念的框架,在该框架中以系统的方式定义了数据库用户的数据需求,以及满足这些需求的数据库结构
最初阶段:完整地刻画未来数据库用户的数据需求
概念设计
:选择数据模型,并采用所选的数据模型的概念将这些需求转化为数据库的概念模式。它定义了数据库中表示的实体、实体的属性、实体之间的联系以及实体和联系上的约束功能需求规格说明
:用户描述将在数据上进行的各类操作(事务)
,操作例子包括有修改或者更新数据,搜索并取回特定的数据以及删除数据。从抽象数据模型到数据库实现的转换过程将在最后两个设计阶段中进行
- 在逻辑设计阶段
(logocal-design phase)
中,设计者将高层概念模式映射到将使用的数据库系统的实现数据模型上。实现数据模型通常是关系数据模型,该阶段通常包括将以实体-联系模型定义的概念模式映射到关系模式 - 最后设计者将所得到的系统特定的数据库模式使用到后续的
物理设计阶段(physical-design phase)
,在该阶段,指明数据库的物理特征,这些特征包括文件组织格式
和索引结构的选择
。
- 在逻辑设计阶段
1.2 设计的选择
我们使用实体(entity)
这个术语来指示所有可明确识别的个体,这些各种各样的实体以多种方式互相关联,而所有这些方式都需要在数据库设计中反映出来。例如说一名学生在一次开课中选课,而一名教师在一次开课中授课。授课
、选课
就是实体间联系的实例
在设计数据库的时候,我们必须确保避免两个主要的缺陷
- 冗余:一个不好的设计可能会导致重复的信息保存。冗余可能出现在关系模式中,信息的这种冗余表达的最大问题就是当对一条信息进行更新但是没有将这条信息的所有拷贝都更新的时候,那么这条信息的拷贝将会不一致。理想的情况下,信息应该只出现在一个地方
- 不完整:一个不好的设计可能会使得某些方面难于甚至无法建模,比如说,如果我们设计了这样的关系模式:我们只有对应于开课的实体而没有对应于课程的实体,如果我有一门新课程,但是这门新课程还没有开,可能要到下学期之类的才能开,但是这时候已经申请备案,要把这门课保存到云上,这时候的这种设计就存在了问题,就是这门课到底要放哪里去呢?从这个角度上看,这就是设计过程中产生的数据不完整的缺陷。
2. 实体-联系模型
实体-联系(entity-relationship,E-R)
数据模型的提出旨在方便数据库的设计,它是通过允许定义数据库全局逻辑结构的企业模式实现的。
E-R
数据模型采用了三个基本概念:实体集
、联系集
和属性
2.1 实体集
实体(entity)
:是现实世界中可区别于其他对象的一个事物或者对象,每个实体有一组属性,其中一些性质的值可以唯一地表示一个实体。
实体集(entity set)
:是指相同类型也就是具有相同性质(属性)
的一个实体集合,这个对应于数据库中的表,例如说大学数据库中的实体集instructor
这样的东西
实体通过一组属性(attribute)
来表示,属性是实体类中每个成员所拥有的描述性性质
,为某实体集指定一个属性表明数据库为该实体集中每个实体存储相似的信息。
每个实体的每个属性都有一个value
数据库包括一组实体集,每个实体集包括任意数量的相同类型的实体
2.2 联系集
联系(relationship)
:是指多个实体间的相互关联。
联系集(relationship set)
:是相同类型联系的集合,正规地说,联系集是n>=2
个可能相同的实体集上的数学关系,如果E1,E2,...,En
是实体集,那么联系集R可以表示为{(e1,e2,...,en)|e1∈E1,e2∈E2,...,en∈En}
的一个子集,而(e1,e2,...,en)
就是一个联系
实体集之间的关联称为参与,也就是说实体集E1,E2,...,En
参与联系集R
,E-R
模式中得一个联系实例relation instance
表示在所建模的显示世界企业中命名实体间的一个关联
实体在联系中扮演的功能称为实体的角色role
,参与一个联系集的实体通常是互异的。但当参与一个联系集的实体不是互异的时候,同样的实体集以不同的角色参与一个联系集于一次的时候,这种实体集叫做自环(recursive)也叫做递归的
联系集,有必要用显式的角色名来指明实体是如何参与联系实例的。
比如说
prereq
用来描述一门课程(C2)是另一门课程(C1)的先修课程。每对课程中的第一门课程具有C1
的角色,而第二门课程具有先修课C2
的角色,按照这种方式,就能够将所有的联系通过(C1,C2)
对进行表示,而排除了(C2,C1)
联系也可以具有描述性属性(descriptive attribute)
2.3 属性
每个属性都有一个可取值的集合,称为该属性的域domain
,或者值集(value set)
正式地说,实体集的属性是将实体集因映射到域的函数。由于一个实体集可能有多个属性,因此每个实体可以用一组(属性,数据值)
对进行表示,实体集中的每个属性对应一个这样的对。
E-R模型中的属性可以按照如下的属性类型进行划分
- 简单(simple)和复合(composite)属性
简单属性不能被划分为更小的部分,而复合属性可以再划分为其他属性。
- 单值属性和多值属性
对于某个特定的学生实体而言,
student_ID
属性只对应于一个学生ID,这样的属性叫做是单值的。而在某些情况下对某个特定实体而言,一个属性可能对应于一组值,比如说如果老师有设定电话号码的这个属性的话,我们就认为这个属性是多值的,因为老师可能有若干个电话号码
- 派生属性
这类属性的值可以从别的相关属性或者实体派生出来,比如说
instructor
实体集中有一个属性students_advised
,表示这个教师指导了多少个学生,我们可以通过统计与一个教师相关联的所有student
实体的数目来得到这个属性的值。值得注意的是,我们一般记录下来的是基属性,而对于派生属性而言,我们在必要的时候通过基属性计算出来
当实体在某个属性上没有值的时候使用空null
值,空值可以用来表示不适用,也就是这个实体的这个属性是没有值的。
3.约束
E-R企业模式
可以定义一些数据库中的数据必须要满足的约束。
3.1 映射基数
映射基数(mapping cardinality)
,或者基数比例,表示一个实体通过一个联系集能关联的实体的个数。
映射基数在描述二元联系集的时候非常有用,他们也可以用于描述涉及多于两个实体集的联系集。
对于实体集A和B之间的二元联系集R来说,映射基数必然是以下情况之一:
一对一(one to one)
:A中的一个实体至多与B中的一个实体相关联,并且B中的一个实体也至多与A中的一个实体相关联一对多(one-to-many)
:A中的一个实体可以与B中任意数目(零个或者多个)
实体相关联,而B中的一个实体至多与A中的一个实体相关联多对一(many-to-one)
:A中的一个实体至多与B中的一个实体相关联,而B中的一个实体可以与A中任意数目(零个或者多个)
实体相关联多对多(many-to-many)
:A中的一个实体可以与B中任意数目(零个或者多个)
实体相关联,而且B中的一个实体也可以与A中任意数目(零个或者多个)
实体相关联
例子:考虑这样一种场景,一名学生值能由一名教师指导,而一名教师可以指导多个学生,那么
instructor
到student
的联系集是一对多的。结论是,如果
instructor
作为A实体集,而student
作为B实体集,A中的一个实体可以与B中任意数目(零个或者多个)
实体相关联,而B中的一个实体至多与A中的一个实体相关联
3.2 参与约束
全部(total)
:如果实体集E中的每个实体都参与到联系集R
的至少一个联系中,实体集E
在联系集R
中的参与称为全部的部分的(partial)
:如果E中只有部分实体参与到R
的联系中,实体集E
到联系集R
的参与称为部分的
例如,我们希望每个
student
通过aadvisor
联系同至少一名教师相联系,因而student
在联系集advisor
中的参与是全部的,相反地,一个instructor
并非一定要指导一个学生,因此,很有可能只有一部分instructor
实体通过advisor
联系同student
实体集相关联,于是,在这种情况下我们说instructor
这个实体集在advisor
的联系集中的参与是部分的。
3.3 码
我们必须有一个区分给定实体集中实体的方法,从概念上来说,各个实体是互异的,但是从数据库的观点来看,它们的区别必须通过其属性来表明
一个实体的属性的值必须可以
唯一标识该实体
,也就是说,在一个实体集中不允许两个实体对于所有属性都具有完全相同的值。
复习:关系模式中的超码、候选码、主码
- 超码
超码也叫做
super key
,直接翻译过来就是超级码,它是一个或者多个属性的集合,这些属性可以让我们在一个实体集中唯一地标识一个实体,如果K是一个超码,那么K的任意超集也会是超码。也就是说K如果是超码,那么所有包含K的集合也是超码注:超集是集合论中的术语,如果A包含B,那么A集就是B的超集,也就是说B的所有元素A中都有,但是A中的元素B未必有。
(A是大范围,B是小范围)
- 候选码
超码包括候选码
(candidate key)
,虽然说超码能够唯一地标识一个实体,但是可能大多数超码中含有多余的属性,所以我们需要候选码。如果关系中的一个属性或者属性组能够唯一地标识一个元组,而且它的真子集不能唯一的标识一个元组,则称这个属性或者属性组做候选码子集比自己的范围要大,子集是包含本身的元素的集合,真子集是除了本身的元素的集合
- 主码
一个表的候选码可能有多个,从这些个候选码中选择一个作为主码,至于具体是哪一个候选码,这个可以需求选择。
码同样适用于唯一地标识联系,并从而将联系互相区分开来。
实体集的主码使得我们可以区分实体集中不同的实体,我们需要一种类似的机制来区分联系集中不同的联系。
设R
是一个涉及实体集E1,E2,...,En
的联系集,设主码(Ei)
代表构成实体集Ei
的主码属性集合,目前假设所有的主码的属性名是互不相同的。联系集主码的构成依赖于同联系集R
相关联的属性集合。
如果联系集R中没有属性与之相关联,属性集合primary-key(E1)∪primary-key(E2)∪primary-key(E3)∪...∪primary-key(En)
描述了集合R
中的一个联系。
如果联系集R中有属性a1,a2,...,am
与之相关联,那么属性集合
primary-key(E1)∪primary-key(E2)∪...∪primary-key(En)∪{a1,a2,...,am}
描述集合R上上的一个联系。
在以上的两种情况下,属性集合primary-key(E1)∪primary-key(E2)∪....∪primary-key(En)
性成交价鞥了联系集的一个超码
如果实体集间主码的属性名称相同,那么我们就需要重命名这些属性,一般的手段可以 是实体集+属性名
这样就可以构成唯一的名称。
如果实体集不止一次参与某个联系集,那么就可以使用角色名代替实体集名构成唯一的属性名(C1、C2)
联系集的主码结构依赖于联系集的映射基数。例如
instructor
和student
以及具有属性date
的联系集advisor
。
- 考虑联系集是多对多的,那么
advisor
的主码应该由instructor和student的主码并集组成- 考虑联系集是从student到instructor是多对一,也就是说每个学生只能有一个导师,那么如果我有
student
的主码,就能够唯一确定这个联系,因此在这种情况下student
的主码就是advisor
的主码- 考虑联系集是一对一的,两个候选码中的任意一个均可以作为联系集的主码
4. 从实体集中删除冗余属性
当使用E-R
模型设计数据库的时候,通常从确定那些应该包含的实体集开始,一旦选择号实体和它们相应的属性,不同实体间的联系集就建立起来了。这些联系集有可能会导致不同实体集中的属性冗余,并需要将其从原始实体集中删除。
例子:考虑实体集instructor
和department
- 实体集instructor包含属性
ID
、name
、dept_name
、salary
,其中ID构成主码 - 实体集department包含属性
dept_name
、building
、budget
,其中dept_name
是主码
我们用关联instructor
个department
的联系集inst_dept
对每个教师都有一个关联的系的情况进行建模。
属性dept_name
在两个实体集中都出现了,由于它是实体集department
的主码,因此它在实体集instructor
中是冗余的,需要进行移除。
当我们从
E-R
图构建一个关系模式的时候,只有当每个教师最多只与一个系关联的时候,我们才会将属性dept_name
添加到关系instructor
中.如果一个教师有多个关联系的时候,教师与系之间的联系会记录在一个单独的关系inst_dept
中
在这里,将教师和系之间的关联统一看成联系,而不是instructor
的一个属性,可以使得逻辑关系明确,并有助于避免过早地假设每个教师只与一个系关联。
5. 实体-联系图
5.1 基本结构
分成两部分的矩形
代表实体集。包含有实体集的名字,第二部分包含实体集中所有属性的名称菱形
:代表联系集未分割的矩形
:联系集的属性构成主码的属性以下划线标明线段
:将实体集连接到联系集虚线
:将联系集属性
连接到联系集双线
:显示实体在联系集中的参与度双菱形
:代表连接到弱实体集的标志性联系集
5.2 映射基数
一对一
: 从联系集advisor
向实体集instructor
和student
各画一个箭头,这表示一个教师可以知道至多一名学生,而且学生至多有一位导师。
一对多
:一名教师可以指导多名学生,而一名学生至多值能有一名导师。
多对一
:表示一名教师可以指导至多一名学生,但是一名学生可以有多位导师。多对多
:一名教师可以指导多名学生,并且一名学生可以有多位导师。
E-R
图还提供了一种描述每个实体参与联系集中联系的次数的更复杂的约束的方法,实体集和二元联系集之间的一条边可以有一个关联的最大和最小的映射基数
,用l...h
的形式进行表示,其中l
表示最小的映射基数,而h
表示的是最大的映射基数。
举例
考虑上图,在advisor
和student
之间的边有1...1
的基数约束,这意味着基数的最小值和最大值都是1,也就是说每个学生必须有且仅有一个导师。
从advisor
到instructor
边上的约束0...*
说明教师可以有零个或者多个学生,*表示没有上限。
由于student
和advisor
之间的边有1..1
的基数约束,也就是说最小的基数约束是1个学生对应一个联系,那么也就是说一个学生必须有一个导师,也只能有一个导师。
深入理解:这个
0..*
表示的是,在实体集能够建立的联系个数,l表示的是这个实体集中,每个实体所能建立的最小联系个数,h表示的是这个实体集中,每个实体所能建立的最大联系个数。
- 对应到图上,也就是
instructor
这个实体集上,每个实体能够建立的最小联系个数是0
,翻译过来就是教师可以不与学生建立advisor
的联系,也就是说教师不一定要成为导师,同时,它能够建立最多n个联系,也就是说能够成为n个学生的导师student
能够建立的最小联系个数是1
,最大联系个数是1
,也就是说每个学生必须要建立一个联系,而且最多只能有一个联系,那么也就是说一个学生最多只能与一个老师建立一个advisor
的联系
注E-R图的另一种画法是在基数约束的位置画一条从student到advisor的双线,以及一个从advisor到加structor的箭头。这种画法可以强制实施同图7-10中所示约束完全一样的约束。
5.3 复杂属性表示法
5.4 角色标识
5.5 弱实体集
考虑一个section
实体,它由课程编号
、学期
、学年
、开课编号
唯一标识,开课的实体和课程实体相关联,假设我们在实体集section
和course
之间创建了一个联系集sec_course
现在发现sec_course
中的信息是冗余的,由于section
已有属性course_id
,它表示该开课与所关联的课程,有两种消除冗余的方法
- 删除联系
sec_course
,这样做使得section
和course
之间的联系隐含于一个属性中,这不是我们想要的 - 在实体中删除属性
course_id
,而只保存剩下的属性sec_id
、year
以及semester
,然而,这样的话实体集section
就没有足够的属性去唯一地标识一个指定的section
,这是因为规定了不同课程的开课也可能会有相同的sec_id
、year
、semester
。为了解决这个问题,可以将联系sec_course
视为一个特殊的联系,它给唯一标识section
实体提供额外的信息,也就是course_id
没有足够的属性以形成主码的实体集称为
弱实体集
,有主码的实体集称为强实体集
弱实体集
必须与另一个称作标识
或者属主实体集的实体集
关联才能有意义,每个弱实体必须和一个标识实体关联。也就是说弱实体集是存在依赖于标识实体集
。我们称实体集拥有它所表示弱实体集
,将弱实体集与其表示实体集相关联的联系称为标识性联系。
依赖:弱实体应该依赖于强实体
主键:弱实体的主键是组合主键
(其他实体的主键组成的)
在例子中,section
的标识实体集是course
,将section
实体和它们对应的course
实体关联在一起的sec_course
是标识性联系。
虽然弱实体集没有主码,但是我们依然需要区分依赖于特定强实体集和弱实体集中实体的方法(就是知道这个弱实体集描述的是哪个一个强实体集的信息)
。
弱实体集的分辨符是使得我们进行这种区分的属性集合。这个属性集唯一标识了这门课程的一次开课,弱实体集的分辨符也称为该实体集的部分码
弱实体集
的主码由标识实体集的主码加上该弱实体集的分辨符构成。
例如在实体集section
,它的主码是{course_id,sec_id,year,semester}
,其中course_id
是标识实体集course
的主码,{sec_id,yaer,semester}
是区分同一门课程的不同section
实体。
那么到了这里,一直有个困惑,如果sec_id
会重复,那么我使得每一门开课的section
的sec_id
不重复不就好了吗?
当然是可以的,在这种情况下,实体集section
将会拥有一个主码,然而,一个section
的存在的概念上依然依赖于一个course
,通过使之成为弱实体集可以明确这种依赖关系。
这就是弱实体集存在的意义。
在E-R
图中,弱实体集和强实体集是类似的,以矩形来表示,但是有以下区别:
- 弱实体集的分辨符以虚下划线表明,而不是实线
- 关联弱实体集和标识性强实体集的联系集以双菱形表示
细节
弱实体集section
在联系sec_course
中的参与是全部的,表示每次开课必须通过sec_course
与某门课程关联,最后从sec_course
指向course
的箭头表示每次开课与单门课程相关联- 除此之外,弱实体集还能够作为属主与另一个实体集参与一个标识性的联系。一个弱实体集也可能与不止一个表示实体集关联。
6. 转换为关系模式
对于每个实体集以及每个联系集,都有唯一的关系模式与之对应,关系模式名也就是相应的实体集或者联系集的名字
6.1 具有简单属性的强实体集的表示
设E只是具有简单描述属性a1,a2,..,an
的强实体集,我们用具有n个不同属性的模式E
来表示这个实体集,该模式的关系中的每个元组同实体集E的一个实体相对应
对于强实体集转换而来的模式,强实体集的主码就是生成的模式的主码,这个结论是从每个元组都对应于一个实体集中一个特定实体这个实时得到的。
6.2 具有复杂属性的强实体集的表示
需要通过为每个子属性创建一个单独的属性来处理复合属性,并不为符合属性自身创建一个单独的属性。
多值属性需要创建新的关系模式,比如说教师的phone
可以构建一个关系模式R,该模式包含一个对应于M的属性A,以及对应于M所在的实体集或者联系集的主码的属性
6.3 弱实体集的表示
设A是具有属性a1,a2,...,an
的弱实体集,设B是A所依赖的强实体集,设B的主码包括属性b1,b2,...,bn
我们用名为A的关系模式表示实体集A,该模式下的每个属性对应以下集合中的一个成员
{a1,a2,a3,...,an}∪{b1,b2,...,bn}
依据是从弱实体集转换而来的模式.该模式的主码由其所依赖的强实体集的主码与弱实体集的分辨符而成。
除了创建主码之外,还要在关系A上建立外键约束,该约束表明属性b1,b2,...,bn
参照关系B的主码
6.4 联系集的表示
对于多对多的二元联系,参与实体集的主码属性的并集成为主码
对于一对一的二元联系集,任何一个实体集的主码都可以作为主码
对于多对一或者一对多的二元联系集,联系集中多的那一方的实体集的主码构成主码。
对于边上没有箭头的n元联系集,所有参与实体集的主码属性的并集称为主码
对于边上有一个箭头的n元联系集,不在箭头测的实体集的主码属性为模式的主码
课后习题解答
为车辆保险公司构建一个ER图,
- 它的每个
客户
有一辆或多辆车
。 每辆车
关联零
次或任意
次事故的记录。每张保险单
为一
辆或多
辆车保险,并与一
个或多个
保费支付
相关联,每次支付
只针对特定的一段时间,具有关联的到期日和缴费日
。