在前面的学习中,我们已经掌握了如何使用 SQL 对现有数据库进行查询与更新。接下来,我们将深入探讨一个更为根本且关键的问题:如何从零开始系统性地设计数据库结构。这一过程类似于建筑工程中在动工前必须先制定详尽的蓝图。
数据库设计是一个高度专业化且至关重要的环节,其质量直接决定了系统的性能、可维护性与可扩展性。例如,在为电商平台进行数据库设计时,若缺乏科学的规划与建模,后续在订单处理、库存管理、用户信息维护等核心业务环节中将不可避免地面临数据冗余、查询低效、数据一致性难以保障等诸多问题。

对于简单的应用程序,经验丰富的设计师可能可以直接确定需要创建哪些表、它们的属性以及表之间的约束关系。但对于现实世界中的复杂应用,这种直接设计的方法就显得力不从心了。原因很简单:现实应用往往非常复杂,通常没有一个人能够完全理解应用的所有数据需求。
举个例子,假设我们要为一所大学设计数据库系统。这个系统需要处理学生信息、教师信息、课程安排、成绩管理、图书馆管理、财务管理等众多方面。显然,没有人能够独自掌握所有这些领域的详细需求。
数据库设计师必须与领域专家和用户广泛交流,以便全面理解应用需求,并将这些需求转化为数据库结构。
一个完整的数据库设计过程通常包含以下几个阶段:
需求分析阶段
需求分析是数据库设计流程的起点,也是决定后续设计成败的关键环节。在此阶段,设计人员需与业务领域专家、最终用户等多方深入沟通,全面、系统地收集和梳理企业对数据的各项需求。例如,在电商平台数据库设计中,需明确商品信息的结构与粒度、订单数据的组成字段、用户信息的详细程度等。需求分析的最终产出为一份详尽、规范的用户需求说明文档,为后续设计提供权威依据。
概念设计阶段
在充分理解并归纳用户需求后,设计师需选定合适的数据模型,并基于该模型将需求转化为抽象的概念模式。概念模式全面刻画了企业数据及其相互关系的本质结构。实体关系模型(E-R模型)是概念设计阶段最常用的建模工具,它能够系统地识别出数据库中的实体类型、属性、实体间的各种关系及其约束条件。概念设计的核心成果通常为实体关系图(E-R图),以图形化方式直观展现数据库的整体逻辑结构。此阶段关注的是数据及其语义关系的表达,而非具体的物理实现细节,类似于建筑设计中的功能分区与空间布局规划。
功能需求确认
完善的概念模式还需覆盖企业的功能性需求。功能需求说明书应明确用户在数据层面期望实现的各类操作类型,如数据的增删改查、复杂检索、批量处理等。设计师需在概念设计阶段对模式进行功能性校验,确保其能够支撑所有预期的业务操作。
逻辑设计阶段
逻辑设计阶段的任务是将高层次的概念模式映射为特定数据库管理系统支持的实现数据模型。通常,这一过程涉及将E-R模型转化为关系模型,明确各实体、关系及属性在数据库中的表结构、字段类型及约束条件等。
物理设计阶段
物理设计阶段聚焦于数据库的底层实现细节,包括数据文件的物理存储结构、索引策略、分区方案、访问路径优化等。合理的物理设计能够显著提升数据库的性能、可扩展性与维护性。
数据库的物理模式可以在应用构建后相对容易地修改,但逻辑模式的修改通常比较困难,因为这可能影响分散在应用代码中的众多查询和更新语句。
在数据库设计过程中,我们必须确保避免两个主要陷阱:
冗余是指同一信息被不必要地重复存储。比如,如果我们在存储课程信息时,每次记录某个课程的开课情况都同时存储课程标识符和课程标题,那么课程标题就被冗余存储了。更好的做法是只存储课程标识符,而将标题信息与课程标识符关联一次即可。
冗余的最大问题是信息副本可能变得不一致。假设某门课程的标题发生了变化,如果我们没有同时更新所有存储该标题的地方,就会出现同一门课程在不同地方显示不同标题的情况。这会让人困惑:到底哪个标题是正确的?
理想情况下,信息应该只在一个地方出现。
不完整性是指某些企业方面的信息难以甚至无法建模。例如,假设我们只有对应课程开课情况的实体,而没有对应课程本身的实体。这样就无法表示一门新课程的信息,除非该课程已经开课。我们可能尝试通过为开课信息存储空值来解决这个问题,但这种变通方法不仅不够优雅,还可能被主键约束所禁止。
在数据库设计过程中,仅仅避免明显的设计缺陷是不够的,更重要的是在众多可行的良好设计方案中,选择最契合业务需求和系统目标的最优方案。即便是看似简单的业务场景,往往也存在多种建模方式,各自具有不同的优势与适用场景。
以“顾客购买产品”为例,我们可以将“销售”建模为顾客与产品之间的关系,也可以将“销售”本身抽象为一个独立的实体,并分别与顾客和产品建立联系。不同的建模选择将直接影响数据库对业务语义的表达能力、扩展性以及后续维护的复杂度。因此,建模决策不仅仅是技术实现的问题,更涉及对业务本质的深刻理解和抽象能力。
在实际企业级系统中,类似的建模抉择广泛存在于各类实体和关系的设计过程中,这也使得数据库设计成为一项兼具科学性与艺术性的复杂任务。
接下来,我们将系统性地介绍实体-关系(E-R)模型,这是进行数据库概念设计的核心理论工具。 实体关系(E-R)数据模型是为了便于数据库设计而开发的,它允许我们指定一个企业模式,该模式表示数据库的总体逻辑结构。
E-R模型在将现实世界企业的含义和交互映射到概念模式上非常有用。正因为这种实用性,许多数据库设计工具都采用了E-R模型的概念。E-R数据模型采用三个基本概念:实体集、关系集和属性。我们先学习这些基本概念,然后再学习E-R模型相关的图形表示法——E-R图。

实体是现实世界中可区别于其他对象的“事物”或“对象”。例如,一所大学中的每个学生都是一个实体。每个实体都有一组属性,某些属性的值可能唯一标识一个实体。比如,一个学生可能有学号属性,其值能唯一标识这个特定的学生。类似地,课程可以被看作实体,课程编号能唯一标识一个课程实体。
实体可以是具体的,如某个人或某本书;也可以是抽象的,如某门课程、某次课程开课或某个航班预订。
实体集是相同类型且具有相同属性的实体的集合。例如,某所大学的所有教师可以定义为实体集“教师”。类似地,实体集“学生”可以表示该大学的所有学生。
在建模过程中,我们经常在抽象意义上使用术语“实体集”,而不涉及特定的个体实体集合。我们使用术语“实体集的外延”来指代属于该实体集的实际实体集合。因此,某大学的实际教师集合构成了实体集“教师”的外延。这种区别类似于我们在之前看到的关系和关系实例之间的区别。
实体集不需要是不相交的。例如,可以定义大学中所有人的实体集“人员”。一个人实体既可以是教师实体,也可以是学生实体,或者两者都是,或者都不是。
实体通过一组属性来表示。属性是实体集每个成员所拥有的描述性属性。实体集的属性指定表示数据库存储关于该实体集中每个实体的类似信息;然而,每个实体对于每个属性可能有自己的值。 让我们看一个具体的例子。假设我们要为一个在线购物平台设计数据库:
对于商品实体集,我们可能需要这些属性:商品编号用于唯一标识商品,商品名称表示商品的名称,价格记录商品的售价,分类标明商品所属的类别,库存数量显示当前的库存情况。
对于用户实体集,典型的属性包括:用户ID用于唯一标识用户,用户名表示用户的账户名,手机号作为用户的联系方式,注册时间记录用户注册的时间。
每个实体对每个属性都有一个值。例如,某个具体的商品实体可能具有这样的属性值:商品编号为“P001”,商品名称为“华为手机”,价格为3999,分类为“电子产品”,库存数量为50。这意味着该实体描述了一部售价为3999元的华为手机,商品编号为P001,属于电子产品分类,当前库存50台。
关系集(Relationship Set)用于建模多个实体集之间的逻辑关联。在E-R模型中,关系集反映了现实世界中实体之间的语义联系。例如,关系“购买”可用于表达“用户”与“商品”之间的购买行为,如“用户张三购买了华为手机”。
关系集是同类型关系的集合。从形式化角度看,关系集是定义在n(n≥2)个实体集E₁、E₂、...、Eₙ上的数学关系。设R为关系集,则R是E₁×E₂×...×Eₙ的子集,其中每个元组(e₁, e₂, ..., eₙ)代表一个具体的关系实例。
以电商平台为例,设有实体集“用户”和“商品”,则“购买”关系集用于描述用户与其所购商品之间的对应关系。
实体集与关系集之间的联系称为“参与”。即,实体集E₁、E₂、...、Eₙ参与关系集R。E-R模式中的每个关系实例均对应于被建模业务中的实体间实际关联。
在关系中,实体所承担的语义功能称为“角色”。通常,不同实体集参与同一关系集时,角色是隐含的,无需显式标注。但在同一实体集多次参与同一关系集(即自引用或递归关系集)时,需通过角色名加以区分。
例如,设实体集“课程”用于记录高校开设的所有课程。为描述课程间的先修关系,可定义关系集“先修”,其每个关系实例为有序对(C1, C2),表示课程C1以C2为先修课程。此时,C1和C2分别承担“后续课程”和“先修课程”的角色。
关系集不仅可以连接实体,还可附加描述性属性,用于刻画关系本身的特征。例如,在“购买”关系集中,可关联属性“购买日期”,以记录用户购买商品的具体时间。若“用户张三”与“华为手机”之间存在“购买”关系,且“购买日期”为“2024年3月15日”,则该关系实例完整地表达了“张三于2024年3月15日购买了华为手机”。
再如,实体集“学生”与“课程”通过“选课”关系集关联。此关系集可附加属性“成绩”用于记录学生在该课程中的成绩,或“学分类型”以区分正式选课与旁听等情况。
关系集中的每个关系实例必须能够仅通过参与实体的主键唯一标识,描述性属性不得作为区分关系实例的依据。
每个属性均关联一个允许取值的集合,称为该属性的域(Domain)或值集。例如,属性“商品价格”的域可定义为所有正实数的集合;属性“商品分类”的域可为“电子产品”、“服装”、“食品”、“图书”等有限字符串集合。
从形式化角度,实体集的属性可视为从实体集到其域的映射函数。由于实体集通常包含多个属性,每个实体可由一组(属性,属性值)对唯一刻画。
例如,某一商品实体可用如下属性-值对描述:商品编号=P001,商品名称=华为手机,分类=电子产品,价格=3999元。该组属性值完整地定义了该商品实体的状态。
E-R模型中,属性类型主要包括以下几类:
简单属性(Simple Attribute)不可再分解为更小的组成部分。例如,商品编号、价格等均为简单属性。
复合属性(Composite Attribute)可进一步分解为若干子属性。例如,属性“姓名”可细分为“姓”、“名”、“中间名”;属性“地址”可分为“街道”、“城市”、“省份”、“邮政编码”等。复合属性可呈现多级层次结构,如“街道”可进一步细分为“街道号”、“街道名”、“单元号”等。
在数据建模时,复合属性适用于既需整体引用属性,又需单独访问其组成部分的场景。
单值属性(Single-valued Attribute)在每个实体实例上仅取唯一值。例如,学生的“学号”属性对每个学生实体仅有一个值。
多值属性(Multi-valued Attribute)允许某一实体实例对应属性的取值为一个值集。例如,用户的“电话号码”属性可能包含零个、一个或多个电话号码。多值属性通常以花括号表示,如 {电话号码}、{邮箱地址}。
对于多值属性,可根据业务需求设定取值的上下界。例如,某系统可规定每个用户最多登记两个电话号码,则该属性的取值基数为0~2。
派生属性(Derived Attribute)是指其值可由其他属性或实体的相关信息计算得出,无需在数据库中显式存储。例如,用户的“订单总数”可通过统计与该用户关联的订单实体数量获得;“年龄”属性可由“出生日期”与当前日期计算得出。在此情形下,“出生日期”为基属性(Stored Attribute),而“年龄”为派生属性。派生属性的值通常在查询时动态计算。
当某实体在某属性上无有效取值时,该属性取空值(Null)。空值的语义包括:
例如,若用户的“姓名”属性为空,通常视为缺失(应有但未提供);若“邮箱地址”属性为空,可能表示该用户无邮箱(不适用)、有邮箱但未知(缺失),或不确定是否有邮箱(未知)。
理解属性类型及空值的语义,有助于在E-R建模过程中准确表达业务规则和数据约束。
E-R模型允许定义多种约束条件,以确保数据库内容的正确性和一致性。我们将重点讨论映射基数约束与参与约束。

映射基数(又称基数比,Cardinality Ratio)用于描述一个实体通过某一关系集能够关联的其他实体的数量。该约束在二元关系集中应用最为广泛,尽管在多元关系集中同样适用。以下仅讨论二元关系集的典型映射基数类型:
实体集A中的每个实体至多与实体集B中的一个实体相关联,反之亦然。
示例:在企业信息系统中,假设每个部门仅对应一位部门经理,且每位员工最多只能担任一个部门的经理,则“管理”关系为部门与员工之间的一对一关系。
实体集A中的一个实体可以与实体集B中的多个实体相关联,但实体集B中的每个实体至多只与实体集A中的一个实体相关联。
示例:在组织结构中,一个部门可拥有多名员工,但每名员工仅属于一个部门,则“隶属”关系为部门到员工的一对多关系。
实体集A中的每个实体至多与实体集B中的一个实体相关联,而实体集B中的一个实体可与实体集A中的多个实体相关联。
示例:多个学生可选择同一门课程,但每个选课记录仅对应一名学生和一门课程。在此场景下,从学生到课程的“选课”关系为多对一关系。
实体集A中的一个实体可与实体集B中的多个实体相关联,实体集B中的一个实体同样可与实体集A中的多个实体相关联。
示例:在高校教务系统中,学生与课程之间的“选课”关系通常为多对多关系,即一个学生可选多门课程,一门课程也可被多名学生选修。
关系集的具体映射基数应依据实际业务需求和现实世界的约束进行建模。
以网上书店为例,若规定每位顾客每次仅能购买一本书,且每本书仅能被一位顾客购买,则“购买”关系为一对一关系。但在实际业务中,通常一个顾客可购买多本书,同一本书(不同副本)也可被多位顾客购买,此时“购买”关系为多对多关系。
在E-R模型中,实体集E在关系集R中的参与可分为全参与(Total Participation)与部分参与(Partial Participation)。若实体集E中的每一个实体都必须至少参与一次关系R,则称E在R中的参与为全参与;反之,若仅部分实体参与R,则为部分参与。
例如,在高校数据库中,若要求每个学生实体都必须通过“指导”关系与至少一名教师实体关联,则学生在“指导”关系集中的参与为全参与。而教师实体则可能无需指导任何学生,因此教师在“指导”关系集中的参与为部分参与。
再如,在电商平台中,若每个商品都必须归属于某一分类,则商品在“属于分类”关系中的参与为全参与;而某些分类下可能暂时无商品,则分类在该关系中的参与为部分参与。
在数据库设计中,必须为每个实体集定义能够唯一标识实体的属性集合,即键。从理论上讲,实体间本质上是不同的,但在数据库实现中,这种差异需通过属性值加以体现。实体集的键要求:在同一实体集中,不允许存在两个实体在所有属性上的取值完全相同。
关系模式中的超键、候选键、主键等概念同样适用于实体集。实体集的主键(Primary Key)是能够唯一标识实体的最小属性集。超键(Super Key)是包含主键的属性集,候选键(Candidate Key)是最小的超键。
实体集的主键用于唯一标识集合中的每个实体。例如,在网上书店系统中,顾客实体集可包含属性:顾客ID、姓名、邮箱、送货地址等,其中顾客ID作为主键,确保每位顾客的唯一性。书籍实体集可包含ISBN号、书名、作者、价格、库存数量等属性,其中ISBN号作为主键,唯一标识每本书。
对于关系集R(涉及实体集E₁、E₂、...、Eₙ),设primary-key(Eᵢ)为实体集Eᵢ的主键属性集。若关系集R无自身属性,则R的主键为primary-key(E₁) ∪ primary-key(E₂) ∪ ... ∪ primary-key(Eₙ)。若R含有自身属性a₁、a₂、...、aₘ,则R的主键为primary-key(E₁) ∪ ... ∪ primary-key(Eₙ) ∪ 、{a₁, a₂, ..., aₘ}。在这两种情况下,primary-key(E₁) ∪ ... ∪ primary-key(Eₙ)均为R的超键。
关系集主键的选取与映射基数密切相关。以“顾客”与“订单”之间的“下单”关系为例,假设“下单”关系含有属性“下单日期”:
就像我们前面介绍的一样,E-R图(Entity-Relationship Diagram)是一种用于直观、系统地描述数据库整体逻辑结构的图形化建模工具。 E-R图以其结构清晰、表达直观的特点,成为数据库概念设计阶段最为广泛采用的建模方法之一。

E-R图主要由以下核心元素组成:
实体集以矩形框表示,矩形内标注实体集名称。在现代E-R图表示法中,实体的各属性通常直接列于实体名称下方,主键属性以下划线加以区分,便于突出其唯一性约束。
以下以网上书店系统为例,展示实体集的标准化表示方式:
关系集(Relationship Set)在传统E-R图中通常采用菱形(Diamond)表示,菱形内部标注关系集名称,并通过无向线段将相关实体集(Entity Set)与关系集连接。若关系集包含描述性属性,则以椭圆(Ellipse)连接于菱形,清晰展现关系本身的属性特征。
在现代建模工具(如mermaid E-R图语法)中,关系集的表示方式趋于简化,实体集之间的联系通过带有语义标签的连线直接表达,省略了菱形符号,使得关系结构更加直观紧凑。
属性(Attribute)在传统E-R图中以椭圆形表示,并通过线段与实体集或关系集相连。主属性(Key Attribute)通常以下划线标识以突出其唯一性。在现代E-R图(如mermaid语法)中,属性直接列于实体矩形内部,主键属性以“PK”标注,外键属性以“FK”标注,提升了信息密度和可读性。
E-R图中,映射基数(Mapping Cardinality)用于精确描述实体集间的数量约束关系。常见的基数类型包括一对一(1:1)、一对多(1:N)、多对一(N:1)和多对多(M:N)。不同的E-R图表示法采用不同的符号体系来区分这些基数关系。
在mermaid E-R图语法中,基数关系通过不同的连线符号进行区分:
||--|| : 一对一关系||--o{ : 一对多关系}|--|| : 多对一关系}|--|{ : 多对多关系让我们用一个大学管理系统的例子来说明:
参与约束(Participation Constraint)用于描述实体集中的每个实体是否必须参与某一特定关系。根据参与的强制性,参与约束分为:
在 mermaid ER 图中,可以通过关系连线的符号或在关系标签中进行注释,明确表示参与约束。
对于复合属性,我们通常将其分解为组成部分。例如,地址可以分解为街道、城市、省份和邮政编码:
对于多值属性,我们通常创建一个单独的实体来表示。例如,如果一个客户可以有多个电话号码:
弱实体集(Weak Entity Set)是指自身属性不足以唯一标识其实体的实体集,必须依赖于另一个称为强实体集(Identifying/Owner Entity Set)的主键进行唯一标识。 在E-R模型中,弱实体集具有以下专业特征:
在这个例子中,SECTION是弱实体集,因为课程段必须依赖于课程才能存在。section_id、semester和year构成了判别符,结合course_id才能唯一标识一个课程段。
让我们用一个完整的电商平台数据库来演示各种E-R图概念:
这个E-R图展示了电商平台的核心实体和它们之间的关系。注意ORDER_ITEM是一个关联实体,它将多对多的订单-产品关系转换为两个一对多关系。
虽然基本的E-R模型能够描述大多数数据库的结构特性,但在实际建模过程中,某些复杂的业务需求往往需要对E-R模型进行扩展,以更准确地反映数据的语义和层次结构。 本节将系统性地介绍E-R模型的扩展特性,包括:特化(Specialization)、泛化(Generalization)、高层与低层实体集、属性继承以及聚合(Aggregation)等高级建模概念。

为便于阐述这些高级特性,以下内容将以高校信息系统为例,构建一个更具代表性的E-R模型。我们首先定义一个抽象的实体集“人员(Person)”,用于统一描述高校内所有类型的人员。该实体集包含如ID、姓名、地址等通用属性。
在实际应用中,某些实体集内部可能存在具有特定属性或行为的子集。E-R模型通过“特化”机制,将一个通用实体集细分为若干更具体的子实体集,从而更精确地表达数据结构。
以“人员”实体集为例,根据其在高校中的不同角色,可以进一步细分为以下子类:
每类人员类型(如员工、学生等)均由一组属性进行刻画,这些属性不仅包含其父实体集“人员”的全部通用属性,还可扩展为各自特有的属性。例如,员工实体可增加“工资”等属性,学生实体可增加“总学分”等属性。在E-R建模中,将一个广义实体集细分为若干具有特定属性或行为的子实体集的过程称为“特化(Specialization)”。通过特化,可以根据实体是否属于员工、学生或其他子类,实现对“人员”实体集的精细化建模。需要注意的是,特化关系通常是重叠的,即同一实体既可以属于多个子类,也可以不属于任何子类。
下面以现代在线教育平台为例,展示特化的建模方式:
以高校为例,学生实体集可进一步细分为“研究生”和“本科生”两个子类。研究生通常分配有独立办公室,而本科生则归属于特定的住宿学院。每一类学生子实体集均继承“学生”实体集的全部属性,并在此基础上扩展自身特有的属性,实现对不同学生类型的精细化建模。
实体集可以通过多个区分特征进行特化。在我们的例子中,员工实体之间的区分特征是员工执行的工作。另一个共存的特化可能基于该人员是临时员工还是永久员工。
实体集的细化过程体现了自顶向下(top-down)的数据库建模思想,即从抽象的高层实体集出发,逐步将其细分为更具体的子类实体集,每一层的区分特征逐步明确。相对地,也可以采用自底向上(bottom-up)的方法,将多个具有相同属性或行为的具体实体集,通过抽象和归纳,提升为一个更高层次的泛化实体集。
在实际数据库设计中,设计者可能首先识别出如下具体实体集:
包含属性:教师ID、姓名、工资、职称等。
包含属性:秘书ID、姓名、工资、每周工作小时数等。
分析上述实体集可以发现,教师和秘书均具备标识符(ID)、姓名、工资等共性属性。针对这种属性和语义上的共性,可以通过**泛化(Generalization)**机制,将其抽象为更高层的“员工”实体集。泛化是一种“自下而上”的建模手段,用于表达多个低层实体集之间的共性,并将其提升为一个包含关系的高层实体集。在本例中,“员工”作为高层实体集,教师和秘书作为其子类实体集。
下面以互联网公司为例,进一步说明泛化的建模过程:
在特化(specialization)与泛化(generalization)过程中,高层(超类)与低层(子类)实体集之间最核心的机制是属性继承(attribute inheritance)。即,低层实体集自动继承其高层实体集的全部属性。例如,学生(Student)和员工(Employee)均继承自人员(Person)的ID、姓名、地址等属性;在此基础上,学生还具备总学分(total_credits)等特有属性,员工则拥有工资(salary)等专有属性。
属性继承具有递归性,适用于所有层级的子类。例如,教师(Teacher)和秘书(Secretary)作为员工的子类,不仅继承员工的工资属性,还会继承人员的ID、姓名、地址等属性,实现多层级的属性传递。
除属性外,低层实体集还会继承高层实体集参与的所有关系集(relationship set)。这种关系参与的继承同样具有递归性。例如,若人员实体集与部门(Department)存在“所属部门”关系,则所有继承自人员的子类(如学生、员工、教师、秘书等)均自动参与该关系,无需重复建模。
为实现更精确的业务建模,数据库设计师可在泛化结构中引入多种约束,主要包括成员资格约束和重叠/不相交约束。
成员资格约束用于限定实体能否成为某一低层实体集的成员,常见类型包括:
基于条件的成员资格(Predicate-defined):低层实体集的成员资格由高层实体集的某些属性值决定。例如,若高层实体集“学生”包含属性“student_type”,则可通过student_type的取值(如“研究生”或“本科生”)自动将实体划分至“研究生”或“本科生”子类。这类泛化称为属性驱动泛化(attribute-defined generalization)。
用户指定的成员资格(User-defined):低层实体集的成员资格不依赖于属性条件,而由数据库用户或管理员手动指定。例如,大学员工在入职3个月后由管理人员分配至某一工作团队(Team),此时团队作为员工的低层实体集,成员资格由人为决策而非属性自动判定。
以下以电商平台用户分类为例进行说明:
第二类约束关注实体在同一泛化(或特化)结构中能否同时属于多个低层实体集。根据约束类型,低层实体集可分为以下两类:
不相交约束(Disjoint Constraint):该约束要求每个高层实体在同一泛化中至多属于一个低层实体集。即任意实体不能同时属于多个子类。例如,在学生类型的泛化中,实体的student_type属性只能取“研究生”或“本科生”之一,因此每个学生实体仅能归属于一个子类,二者互斥。
重叠约束(Overlapping Constraint):该约束允许高层实体在同一泛化中属于多个低层实体集。即同一实体可以同时出现在多个子类中。例如,在员工与工作团队的泛化中,若允许员工同时参与多个团队,则同一员工实体可同时属于多个团队子类,体现为重叠泛化。
泛化(Generalization)或特化(Specialization)的完整性约束用于规定高层实体集(superclass)中的实体是否必须属于至少一个低层实体集(subclass)。该约束分为以下两类:
在 E-R 建模中,部分泛化是默认约束。对于通过泛化得到的高层实体集,若其所有成员都必须归属于某个子类,则应明确标注为完全泛化。
E-R 模型的一个局限在于其无法直接表达“关系的关系”。为解决此问题,引入了聚合(Aggregation)机制。聚合允许将一个关系集(relationship set)与相关实体集(entity set)共同视为一个更高层次的抽象实体,从而支持关系之间的关联。
以“项目指导”为例,假设存在一个三元关系 PROJECT_GUIDANCE,连接教师(INSTRUCTOR)、学生(STUDENT)和项目(PROJECT)。若需对每个指导关系进行评估(EVALUATION),可将 PROJECT_GUIDANCE 及其相关实体聚合为一个高层实体集,再与 EVALUATION 建立联系。
如果直接在教师、学生、项目和评估之间建立四元关系,会导致冗余和一致性问题,因为每个(教师,学生,项目)组合必须在 PROJECT_GUIDANCE 中已存在。若评估仅为属性,可作为 PROJECT_GUIDANCE 的多值属性;但若评估本身为实体且需与其他实体关联,则应采用聚合建模。
聚合的关键在于:将关系集与其参与实体集共同视为一个复合实体,从而支持更复杂的语义建模,避免冗余和一致性问题。
聚合的一个重要特点是,聚合实体集的主键由其定义关系集的主键构成。不需要单独的关系来表示聚合;从定义关系创建的关系被用作替代。
让我们用另一个例子来进一步说明聚合的概念。考虑一个在线课程平台,其中学生可以参加由不同教师教授的课程。同时,我们需要跟踪学生对每门课程的评价:
这些扩展E-R特性为我们提供了更强大的建模能力,使我们能够更准确地表示复杂的现实世界情况。通过特化和泛化,我们可以创建实体的层次结构;通过聚合,我们可以将复杂的关系作为实体来处理,从而支持更高层次的抽象。
在数据库设计中,E-R模型可通过一组关系模式(Relation Schemas)进行系统化映射。每个实体集(Entity Set)和关系集(Relationship Set)均对应唯一的关系模式,关系模式名称通常与其源实体集或关系集保持一致。
E-R模型与关系模型均为现实世界的抽象与逻辑建模工具。由于二者在建模原则上的高度一致性,E-R模型能够系统地转换为关系数据库模式,实现从概念设计到逻辑设计的无缝衔接。
本节将系统阐述E-R模式到关系模式的映射规则,并说明如何将E-R模型中的各种约束条件(如主键、唯一性、参照完整性等)准确地体现在关系模式的定义中。
设有强实体集E,包含n个简单属性a₁、a₂、...、aₙ。可定义关系模式E(a₁, a₂, ..., aₙ),其中每个属性直接映射为关系模式的一个字段。关系模式中的每个元组唯一对应实体集E中的一个实体。
对于强实体集,主键属性在关系模式中直接作为主键(PRIMARY KEY)实现。这一映射确保了关系中每个元组的唯一性,反映了实体的唯一标识。
以图书管理系统为例,假设实体集“图书”具有属性ISBN、书名、作者,其关系模式定义如下:
|-- 图书实体集转换为关系模式 CREATE TABLE book ( isbn VARCHAR(13) PRIMARY KEY, title VARCHAR(200) NOT NULL, author VARCHAR(100) NOT NULL );
再看另一个例子,对于一个在线购物平台的“用户”实体集:
|-- 用户实体集转换为关系模式 CREATE TABLE customer ( customer_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, phone VARCHAR(20), registration_date DATE NOT NULL );
当强实体集包含复杂属性(如复合属性或多值属性)时,其关系模式的映射需遵循更为严谨的规范。
对于复合属性,应将其分解为若干个最基本的简单属性,并在关系模式中为每个简单属性单独设置字段。复合属性本身不在关系模式中直接体现。
例如,若“用户”实体集存在复合属性“地址”,其下含有“街道(street)”、“城市(city)”、“省份(province)”和“邮政编码(postal_code)”等组成部分,则在关系模式中应分别为这些组成属性建立对应字段:
|-- 包含复合属性的用户实体集 CREATE TABLE customer ( customer_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, -- 地址复合属性被分解 street VARCHAR(100), city VARCHAR(50), province VARCHAR
多值属性的关系模式映射与一般属性不同。通常,E-R图中的单值属性可直接映射为关系模式中的属性字段,而多值属性则需单独建表进行规范化处理。
具体而言,设实体集或关系集E具有多值属性M。应为M单独设计一个关系模式R,R包含如下属性:一是M本身(如电话号码),二是E的主键属性(作为外键引用),二者共同组成R的主键。
例如,假设“用户”实体集(customer)存在多值属性“电话号码”,其主键为customer_id。则应为“电话号码”建立独立的关系customer_phone,结构如下:
|-- 主实体表 CREATE TABLE customer ( customer_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL ); -- 多值属性单独建表 CREATE TABLE customer_phone ( customer_id VARCHAR(20), phone_number VARCHAR
在上述关系模式设计中,用户的每一个电话号码在customer_phone关系中以唯一的元组(tuple)进行存储。具体而言,若某一用户(如customer_id = 'C001')拥有多个电话号码(如"138-1234-5678"与"139-8765-4321"),则customer_phone关系中将分别存在如下两个元组:(C001, 138-1234-5678) 与 (C001, 139-8765-4321)。这种设计确保了多值属性的规范化存储,并通过主键约束(customer_id, phone_number)保证了数据的唯一性和完整性。
派生属性指的是可以通过其他属性计算得到的属性。在关系数据模型中,派生属性通常不直接物理存储于关系模式中,而是在需要时通过查询或计算动态获得。例如,年龄可以通过出生日期和当前日期计算得到。在面向对象数据模型等其他模型中,派生属性可通过方法(method)实现。
设A为弱实体集,具有属性,其依赖的强实体集为B,B的主键由属性组成。弱实体集A的关系模式应包含自身的全部属性以及所依赖强实体集B的主键属性。A的主键由B的主键属性与A的判别符(discriminator)共同组成,从而保证弱实体集元组的唯一性和可区分性。
以下以“课程(course)”与其弱实体集“课程段(section)”为例进行说明:
|-- 强实体集:课程 CREATE TABLE course ( course_id VARCHAR(10) PRIMARY KEY, title VARCHAR(100) NOT NULL, credits INT NOT NULL, department VARCHAR(50) NOT NULL ); -- 弱实体集:课程段(依赖于课程) CREATE TABLE section ( course_id VARCHAR(10
对于由弱实体集映射得到的关系模式,其主键由依赖的强实体集的主键属性与弱实体集的判别符(discriminator)属性联合组成,以确保元组的唯一性。此外,应通过外键约束将强实体集主键属性(如b₁、b₂、...、bₙ)关联至强实体集对应关系的主键,以维护参照完整性。
设R为一个关系集,参与R的所有实体集的主键属性的并集记为a₁、a₂、...、aₘ,R自身的描述性属性(若存在)记为b₁、b₂、...、bₙ。则R的关系模式应包含所有参与实体集的主键属性以及R的所有描述性属性,形式化地表示为R(a₁, a₂, ..., aₘ, b₁, b₂, ..., bₙ)。
关系集主键的选取应遵循规范化设计原则,具体如下:
多对多关系:主键由所有参与实体集的主键属性的并集组成。
|-- 学生选课(多对多关系) CREATE TABLE enrollment ( student_id VARCHAR(20), course_id VARCHAR(10), section_id VARCHAR(5), semester VARCHAR(10), year INT, grade VARCHAR(2), enrollment_date DATE, PRIMARY KEY (student_id, course_id, section_id, semester, year
一对一关系:任一实体集的主键都可以作为主键。
|-- 部门经理(一对一关系) CREATE TABLE department_manager ( department_id VARCHAR(10) PRIMARY KEY, -- 选择部门作为主键 employee_id VARCHAR(20) UNIQUE NOT NULL, start_date DATE, FOREIGN KEY (department_id) REFERENCES department(department_id), FOREIGN KEY (employee_id) REFERENCES employee(employee_id) );
多对一和一对多关系:“多”的一边的实体集主键作为关系的主键。
|-- 员工属于部门(多对一关系) CREATE TABLE works_for ( employee_id VARCHAR(20) PRIMARY KEY, -- "多"的一边作为主键 department_id VARCHAR(10) NOT NULL, hire_date DATE, FOREIGN KEY (employee_id) REFERENCES employee(employee_id), FOREIGN KEY (department_id) REFERENCES department(department_id) );
在基于E-R图的关系模式转换过程中,部分生成的关系模式可能存在冗余,需通过专业方法进行消除或合并以优化数据库结构。
弱实体集与其对应强实体集之间的联系(通常为多对一关系,且无自有描述性属性)在关系模式设计中需特殊处理。由于弱实体集的主键由其自身的判别属性与相关强实体集的主键共同组成,连接弱实体集与强实体集的关系模式中的每一组(强实体主键,弱实体判别属性)在弱实体集自身的关系模式中必然存在。因此,该类联系所对应的关系模式在关系数据库设计中属于冗余项,可予以省略。
以实体集A与实体集B之间的多对一关系集AB为例,按照标准关系模式转换算法,通常会得到A、B和AB三个关系模式。若A在AB关系中的参与度为全参与(即A中的每个实体都必须参与AB关系),则可将A与AB两个关系模式合并,形成一个属性集合为二者并集的新关系模式。合并后关系模式的主键采用被合并实体集(如A)的主键属性。此举不仅消除了冗余,还提升了数据一致性与查询效率。 以下通过具体示例进一步阐释上述合并策略:
|-- 原始设计:三个单独的表 CREATE TABLE instructor ( instructor_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, salary DECIMAL(10,2) ); CREATE TABLE department ( department_id VARCHAR(10) PRIMARY KEY, dept_name VARCHAR
对于包含泛化的E-R图设计关系模式有两种不同的方法:
为高层(父类)实体集单独设计一个关系模式,包含其所有属性及主键。对于每个低层(子类)实体集,也分别设计一个关系模式,包含该子类自身的全部属性,并将高层实体集的主键作为外键(同时也是其主键)纳入子类关系模式中,实现实体间的继承与关联。
|-- 高层实体集 CREATE TABLE person ( person_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(100), phone VARCHAR(20) ); -- 低层实体集:员工 CREATE TABLE employee ( person_id VARCHAR(20)
当泛化满足不相交性(disjoint)和完全性(completeness)约束,即不存在实体同时属于多个子类,且每个高层实体集的实体都必须属于某个子类时,无需为高层(父类)实体集单独设计关系模式。 此时,仅需为每个低层(子类)实体集分别设计关系模式,每个模式应包含该子类自身的全部属性,并补充高层实体集的所有属性,实现属性继承。
|-- 方法二:只为低层实体集创建表(适用于不相交且完整的泛化) CREATE TABLE employee ( person_id VARCHAR(20) PRIMARY KEY, -- 来自高层实体集 name VARCHAR(50) NOT NULL, -- 来自高层实体集 email VARCHAR(100), -- 来自高层实体集 phone VARCHAR(20), -- 来自高层实体集 employee_id VARCHAR(20) UNIQUE NOT NULL
对于包含聚合(Aggregation)的E-R图,其关系模式的设计方法较为直接。聚合本身以及其内部的实体集和关系集,均按照前述的实体-关系转换原则进行关系模式映射。具体而言,聚合可视为一个更高层次的抽象实体或关系,其转换过程通常涉及将聚合内的主码作为外键引入相关表中,以确保数据的完整性与关联性。
以下以“项目指导-评估”聚合为例,说明其关系模式的设计方法:
|-- 基本实体集 CREATE TABLE instructor ( instructor_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, department VARCHAR(50) ); CREATE TABLE student ( student_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50
通过上述系统化的转换规则,可以将任意E-R模型规范地映射为关系数据库模式。这一过程为关系数据库设计提供了理论上的基础和结构化的起点,但在实际应用中,通常还需结合具体业务需求对初步设计进行进一步的优化与规范化处理,以确保数据一致性、冗余最小化及高效性。
让我们用一个完整的电商系统例子来演示整个转换过程:
转换为关系模式:
|-- 1. 强实体集转换 CREATE TABLE customer ( customer_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, phone VARCHAR(20) ); CREATE TABLE product ( product_id VARCHAR(
设计一个图书馆管理系统的数据库。系统需要管理图书、读者和借阅信息。
具体要求:
请给出完整的E-R图设计和关系模式转换。
|-- 图书表 CREATE TABLE book ( book_id VARCHAR(20) PRIMARY KEY, title VARCHAR(200) NOT NULL, author VARCHAR(100) NOT NULL, publisher VARCHAR(100), publication_year INT, isbn VARCHAR(20) UNIQUE,
设计一个大学选课系统的数据库,包含以下实体:
选课记录需要包含:选课学期、学年、成绩。
|-- 学生表 CREATE TABLE student ( student_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, gender CHAR(1) CHECK (gender IN ('M', 'F')), major VARCHAR(50), enrollment_year INT, total_credits
设计一个医院管理系统的数据库,包含以下实体和关系:
就诊记录包含:就诊日期、主诉、诊断结果、处方。
|-- 病人表 CREATE TABLE patient ( patient_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, gender CHAR(1) CHECK (gender IN ('M', 'F')), birth_date DATE, phone VARCHAR(20), address
设计一个电商平台的订单管理系统,包含:
关系说明:
|-- 用户表 CREATE TABLE user ( user_id VARCHAR(20) PRIMARY KEY, username VARCHAR(50) UNIQUE NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, registration_date DATE NOT NULL, user_level VARCHAR(20) DEFAULT '普通' CHECK (user_level
设计一个包含弱实体集的数据库:公司项目管理系统。
实体说明:
|-- 公司表(强实体集) CREATE TABLE company ( company_id VARCHAR(20) PRIMARY KEY, company_name VARCHAR(100) NOT NULL, founding_date DATE, registered_address VARCHAR(200) ); -- 部门表(弱实体集,依赖于公司) CREATE TABLE department ( company_id VARCHAR(20), -- 来自强实体集的主键
设计一个包含多值属性的数据库:员工管理系统。
实体要求:
|-- 员工主表 CREATE TABLE employee ( employee_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, gender CHAR(1) CHECK (gender IN ('M', 'F')), birth_date DATE, hire_date DATE NOT NULL, base_salary DECIMAL
设计一个包含复合属性的数据库:客户地址管理系统。
实体要求:
|-- 客户表(复合属性被分解为简单属性) CREATE TABLE customer ( customer_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, gender CHAR(1) CHECK (gender IN ('M', 'F')), email VARCHAR(100) UNIQUE NOT NULL, registration_date
设计一个包含特化关系的数据库:大学人事管理系统。
高层实体:人员(person)
子类实体:
采用方法一:为每个实体集创建独立的关系模式。
|-- 高层实体集:人员 CREATE TABLE person ( person_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, gender CHAR(1) CHECK (gender IN ('M', 'F')), birth_date DATE, phone VARCHAR(20), email