本节主要涉及数据库的概念和逻辑结构设计,主要掌握E-R图、E-ER图,并掌握如何将这些关系图转化为关系。
数据库设计的基本步骤
了解一下数据库设计的一些阶段:
E-R模型概论
E-R,即Entity-Relationship(实体-关系模型),主要应用在数据库设计的概念设计阶段,已成为里面的一套标准设计工具。E-R图表示了实体型、属性和联系的方法。如下图:
我们需要了解一些概念:
- 实体型:一个物体或概念,例如一个人、一个组织、一架飞机,实体型又可进一步分为:
- 强实体型:可以独立存在的实体
- 弱实体型:依赖于其他实体型存在
- 实体集:一组相同类型的实体集合,比如人类
- 属性:对实体型性质的描述,属性又可细分:
- 简单属性:单一且不可分割的值
- 复合属性:可进一步划分的值
- 关系:实体之间的关联
- 关系的度:参与联系的实体型的数目
实体之间的联系,可以是1v1,也可以是1v多,也可以是多v多,如:
E-R模型符号
掌握E-R图,第一步要掌握的就是E-R图中出现的符号。我们重点掌握下面的几种符号:
有了它们就可以搭建E-R图了。
E-R图
几个基础的E-R图示例:
下面我们以一个实例来分析E-R图的构建过程:
【例】请构建某个工厂物资管理的概念模型。物资管理涉及的实体有:
- 仓库:属性有仓库号、面积、电话号码
- 零件:属性有零件号、名称、规格、单价、描述
- 供应商:属性有供应商号、姓名、地址、电话号码、账号
- 项目:属性有项目号、预算、开工日期
- 职工:属性有职工号、姓名、年龄、职称
这些实体之间的联系如下:
- 一个仓库可以存放多种零件,一种零件可以存放在多个仓库中,因此仓库和零件具有多对多的联系。用库存量来表示某种零件在某个仓库中的数量。
- 一个仓库有多个职工当仓库保管员,一个职工只能在一个仓库工作,因此仓库和职工之间是一对多的联系。
- 职工之间具有领导与被领导关系。即仓库主任领导若干保管员,因此职工实体型中具有一对多的联系。
- 供应商、项目和零件三者之间具有多对多的联系。即一 个供应商可以供给若干项目多种零件,每个项目可以使用不同供应商供应的零件,每种零件可由不同供应商供给。
扩展E-R图(EER图)
上面的E-R图似乎很简单?基本就是按照题目所示,看题画图。扩展的E-R图称为EER图,EER图主要是加入了两种扩展:基数约束和泛化/特化层次。
基数约束
基数约束讲述的是实体型中的任何一个实体可以在联系中出现的最少次数和最多次数。
例如,学生实体型的基数约束是(1, 5),表示每名学生必须学习5~60门课,每门课的学生数从1变化到5不等。
显然,如果min_card >= 1,则表示E全部(强制)参与关系R;如果min_card = 0,则E部分(选择)参与关系R。
有了基数约束后,则原来E-R模型中的1v1,1v多,多v多的关系变为:
泛化
泛化是从给定的语义相关实体集定义广义实体集的过程,是一个抽象的过程。例如,有下面的两类学生:
不难发现,同是学生,都有SSN,Name,GPA属性,区别只在于GRE和SAT不同,我们可以构造超类,如下:
特化
特化是泛化的逆过程,指的是在父实体集中定义子实体集,泛化和特化层次称为IS_A层次。
下面是EER图的一个实例:
上面讲述的是数据库概念结构设计,有了概念结构,接下来我们就应该将概念结构转化为具体的关系表。所谓E-R图转换为关系模型,就是要将实体型、实体的属性和实体型之间的联系转化为关系模式。
E-R图向关系表的转换思路
实体型和属性的转换
实体型和属性的转换很容易,只需要将E-R图中的属性转化为关系表的属性,将E-R图的码属性转化为关系表的码属性,一个实体转化为一个元组,一个实体集转换为一个关系模式。
联系的转换
联系的转换也比较灵活,基本上只要将一个关系转换为一个独立关系模式,或者与联系一端的关系合并(引用外键)。
上面是理论,好像很简单,但实际上我们还是要分几类学习一下具体的转换方法。
【1 vs. 多】关系转换
假设有下面E-R图:
我们可以将关系单独抽取,形成下面关系:
三个关系表 |
---|
Professors (SSN, Name, Rank) |
Students (SSN, Name, GPA) |
advise (Professors.SSN, Students.SSN) |
我们还可以联系advise和Students合并,通过引入外键建立关系表:
两个关系表 |
---|
Professors (SSN, Name, Rank) |
Students (SSN, Name, GPA, Professors.SSN) |
一般惯用将关系 R与m端对应的关系模式合并,在m端关系中加入1端关系的码(做为外键)。
【1 vs. 1】关系转换
我们分情况考虑:
强制参与: 关系R与某一端实体对应的关系模式合并,加入对应关系的码做为外键,这种处理和上面并无两样。
例如上图可转换为:
两个关系表 |
---|
Managers(SSN, Name, Age, Dept.Name) |
Depts(Name, Location) |
部分参与: 同上面方式处理。
一个强制参与,一个部分参与: 这种情况下,我们将联系R并入强制参与的一端,引入外键。如下面例子:
上图是某些特定Employees管理Depts的EER图,分解为下面两表是最佳的:
两表 |
---|
Employees (SSN, Name, Age) |
Depts (Name, Location, Employees.SSN) |
为什么不把Dept.Name并到Employees里面呢?因为等下Employees的Depts.Name会有很多NULL。
【多 vs. 多】关系转换
关系没有属性
- 一个m:n联系转换为一个独立的关系模式
- 含两个外键
关系有属性
- 在关系没有属性的基础上,加上关系上的属性就可以了
例如:
转换为:
三表 |
---|
Students (SSN, Name, Age) |
Course (Course#, Title) |
takes(SSN, Course#, Grade) |
三元关系转换
简单粗暴,将三个或三个以上实体间的一个多元联系转换为一个独立关系模式即可,和上面类似例子差不多,不多讲了。这里举个例子看看:
一元关系转换
一元关系的转换实际上可以转换为二元关系,应用二元关系的转换规则,转换后,删除一个冗余关系,如果没有冗余关系,则删除属性较少的关系。转化为二元关系可以通过建立影子集来实现,如下图示意:
关系表为:
关系表 |
---|
Courses(Course#, Title) |
Prereq(Course#, Prereq_Course#) |
多值属性转换
给多值属性创建一个独立的关系模式。如下图转化为关系表为:
关系表 |
---|
E (A, B) |
E (A, C) |
当然,你说直接E(A, B, C)也无可厚非,但是这会导致数据冗余。因为C是多值属性,等下所有同个C出现的地方,也都会出现大量重复的(A, B),这样效率低下。
复合属性转换
有两种处理方式:
方式一: 直接使用简单属性而忽略其复合属性,转换为:
关系表 |
---|
E (A, D, H, C) |
方式二: 把复合属性转换为一个独立的关系,转换为:
关系表 |
---|
E(A, C) |
E (A, D, H) |
IS_A层次结构转换
方式一: 子类从父类中继承码,转换为:
关系表 |
---|
E (A, B, C) |
E1 (A, D, F) |
E2 (A, G, H) |
方式二: 子类从父类中继承所有属性,转换为:
关系表 |
---|
E (A, B, C) |
E1 (A, D, F, B, C) |
E2 (A, G, H, B, C) |
显然,方式一更应该得到青睐。
复杂EER图的转换
下面是一些转化的规则:
一个实体集转换为一个关系模式(不包含复合属性和多值属性).
- 转换IS_A 层次结构,从上往下.
- 转换多值属性为独立的关系模式.
- 为每个关系确定码
转换联系(关系)
- 一元、二元1-to-1 or 1-to-m 关系, 和并关系到一端,并添加外键.
- 多元关系(>2),联系转换为独立的关系模式,添加码和外键
如上图,有如下的两种转换方式可供参考:
或者是: