课程内容
第一部分:基础理论
数据库系统基本概念(数据模型,体系结构)
关系数据库
关系数据库标准语言SQL
数据库保护
第二部分:设计理论
关系数据理论
数据库设计
第三部分:实现技术
存储管理与索引
查询处理与查询优化
事务处理技术
第四部分:新技术
数据库技术新发展
第一章 概述
数据管理技术的发展
三个基本阶段
1. 人工管理阶段
背景:
存储设备: 外部存储只有磁带、卡片、纸带等,没有磁盘等可直接存取的设备。
软件环境: 没有操作系统,也没有数据管理软件。程序员需要用机器指令或汇编语言编写程序,自行处理数据。
应用领域: 计算机主要用于科学计算,处理的数据量很小。
特点:
数据不保存: 数据通常不长期保存在计算机中,需要时随程序一同输入。
程序与数据高度耦合: 数据与程序不具有独立性。数据的逻辑结构和物理结构由应用程序规定,当数据结构改变时,必须修改相应的程序。
无文件概念: 基本上没有文件的概念,数据组织方式需要由程序员自行设计。
无数据共享: 一组数据对应一个特定的程序,数据是面向应用的,程序间不能共享数据。
2. 文件系统阶段
背景:
存储设备: 出现了磁盘、磁鼓等可以直接存取的设备。
软件环境: 出现了操作系统,其中包含了专门管理数据的软件,即 文件系统。
应用领域: 计算机的应用扩展到了管理领域,如工资管理、库存管理等,需要处理的数据量增大。
特点:
数据长期保存: 数据以 文件 的形式长期保存在外存(如磁盘)上。
记录为单位存取: 数据的存取基本上以记录为单位。
程序与数据有一定独立性: 文件的出现使得程序和数据有了一定的独立性,但这种独立性很有限。
问题与局限:
数据共享性差,冗余度大: 文件仍然是为特定应用程序设计的,文件与应用程序之间基本上是一一对应的关系。这导致当不同应用需要相同数据时,往往会各自建立文件,造成大量数据冗余。
数据不一致性: 由于数据冗余,对同一数据的更新可能无法同步应用到所有副本,导致数据不一致。
程序与数据缺乏独立性: 当文件的逻辑结构(记录的字段、顺序等)改变时,所有使用该文件的应用程序都必须进行相应修改,导致程序维护工作量巨大。
3. 数据库系统阶段
背景:
硬件发展: 出现了大容量的磁盘和光盘。
应用需求: 计算机管理的数据量急剧增大,数据间的关系变得非常复杂,且共享性要求更高(例如,多种应用、不同语言需要共享数据)。
成本变化: 硬件价格下降,而软件价格上升,使得编制和维护应用程序的成本在总成本中占比越来越高。
解决思路:
为了克服文件系统分散管理的弱点,需要实现对数据的 集中控制和统一管理。
这种新的管理方式要求数据是 “集成的” 和 “共享的”。
集成: 指将各种应用相关的数据及其联系,集中地、按照一定结构形式进行存储。
共享: 指数据可以被多个不同的用户或应用所操作。
实现方式:
这种新的需求推动了 数据库技术的产生和发展。
通过一个称为 数据库管理系统 (DBMS) 的核心软件,统一管理和控制所有数据,为上层应用程序提供服务,实现了程序与数据的高度分离(数据独立性)。
数据库系统数据管理特点
数据库系统并非简单地将数据存储起来,而是通过一套复杂的机制,实现了高效、安全、一致的数据管理。其核心特点可以概括为以下五个方面:
特点一:数据结构化,面向全组织的复杂数据结构
数据结构化:
文件系统 仅仅是操作系统中管理文件存放位置的软件,它对文件内部的数据是什么、数据之间有什么关系一无所知。数据在文件内的组织方式完全由应用程序自己定义和解释。
数据库系统 则完全不同,它采用 “数据模型” 来描述和组织数据。这意味着,在存入数据之前,就必须定义好数据的类型、结构以及数据之间的 联系。数据不再是孤立的,而是形成了一个有机的整体。
面向全组织:
文件系统中的数据是“面向应用”的,一个文件通常为一个特定的应用程序服务。
数据库系统中的数据是“面向全组织”或“面向企业”的。它从一个全局的、整体的视角来设计数据,数据不再隶属于某个应用,而是整个组织的公共资源。
特点二:数据冗余度小,易于扩充
这是“数据结构化”和“集成化”带来的直接好处。
数据冗余度小:
因为数据是面向整体、集中管理的,同一个数据项(如某个学生的姓名)在数据库中通常只存储一次。所有需要用到这个数据的应用都从这唯一的数据源获取,从根本上避免了数据冗余。这不仅节省了存储空间,更重要的是,它 避免了数据不一致性 的问题。当数据需要更新时,只需修改一处即可。易于扩充:
由于数据库存储的是整个组织的“全集”数据,当有新的应用需求出现时,往往可以直接利用数据库中的现有数据,或者只需在现有结构上稍作扩充(比如增加一个新的数据项或新的关系),而不需要像文件系统那样重新设计和创建全新的数据文件。这使得系统开发和维护的灵活性和效率大大提高。
特点三:具有较高的数据和程序的独立性
数据独立性是数据库系统的核心目标之一,主要体现在两个层面:
1. 物理独立性
定义: 指用户的应用程序与数据库中数据的 物理存储结构 和 存取方法 是相互独立的。也就是说,当数据的物理存储(比如改变索引方式、更换存储设备、调整文件存放位置等)发生变化时,应用程序 不需要 修改。
实现: 数据库系统通过其三级模式结构中的 “模式/内模式映象” 来实现。当物理层(内模式)改变时,数据库管理员(DBA)可以修改这个映象关系,使得逻辑层(模式)对应用程序来说保持不变。
2. 逻辑独立性
定义: 指用户的应用程序与数据库的 整体逻辑结构 是相互独立的。也就是说,当数据库的整体逻辑结构(模式)发生改变时(例如,在学生表中增加一个“籍贯”字段),只要不影响应用程序用到的数据,那么应用程序就 不需要 修改。
实现: 这由三级模式结构中的 “外模式/模式映象” 来保证。当模式改变时,DBA可以修改这个映象,使得用户原先看到的视图(外模式)保持不变,从而保证了程序的稳定性。
数据独立性大大降低了应用程序的维护成本。在文件系统时代,一点微小的数据结构变动就可能引发所有相关程序的修改,这是一个巨大的负担。
特点四:由DBMS提供统一的数据控制功能
为了保证数据的安全、可靠和正确,所有对数据库的操作都由数据库管理系统(DBMS)统一管理和控制。DBMS提供了以下关键功能:
数据的安全性控制: 通过用户权限管理,保护数据以防止不合法的使用所造成的数据泄密和破坏。
数据的完整性控制: 通过定义一系列的约束条件,保证数据库中数据的正确性、有效性和相容性(例如,学生的成绩必须在0-100分之间)。
并发控制: 在多用户环境下,对用户的并发操作进行控制和协调,以防止操作相互干扰而造成数据不一致。
数据库恢复: 提供一套机制(如日志文件),使得数据库在遭遇故障(如系统崩溃、断电)后,能够将数据库从错误状态恢复到某一已知的正确状态。
特点五:数据的最小存取单位是数据项
在文件系统中,数据的存取通常是以 记录 为单位的。如果你想读取一个学生记录中的姓名,你必须将包含该姓名的整条学生记录都读入内存。
而在数据库系统中,存取单位可以更加灵活。你既可以存取一条或一组记录,也可以只存取记录中的某一个 数据项,也就是我们常说的“字段”。这种灵活性使得数据处理更加高效,减少了不必要的I/O开销。
数据模型
要想实现数据集中存储,面临的首要问题就是:这些来自不同应用、具有复杂联系的数据,在数据库中究竟应该如何组织和表示?数据模型正是解决“集成数据表示”这一问题的有效方式。
一、 两个层次的数据模型
为了兼顾人类的理解方式和计算机的执行方式,数据模型被划分为两个大的层次:
1. 概念模型
目的: 从用户的、现实世界的角度对数据进行建模。它独立于任何具体的机器或DBMS,是现实世界到信息世界的第一层抽象。
作用: 它是数据库设计人员与用户之间进行沟通的语言和工具。特点是易于理解,能够方便、直接地表达应用中的各种语义信息。
最常用的概念模型: 实体—联系方法 (Entity-Relationship Approach),简称 E-R方法。我们通常用 E-R图 来直观地展示概念模型。
2. 数据模型
目的: 从计算机系统的角度对数据进行建模,是概念模型在机器世界的具体实现。它不仅要描述数据的逻辑结构,还要包含对数据的操作和约束。
层次划分:
逻辑模型: 它是我们通常所说的数据模型,如关系模型、层次模型、网状模型等。它描述了数据的整体逻辑结构,是DBMS的核心。
物理模型: 描述数据在存储介质(如磁盘)上的具体存储结构和存取方法,由DBMS负责实现,用户通常不关心。
转换关系:
现实世界业务 → (抽象) → 概念模型 (E-R图) → (转换) → 数据模型 (常常指逻辑模型)
二、 概念模型的核心:E-R方法
E-R方法通过一些基本概念来描述现实世界。
1. E-R模型的基本概念
实体 (Entity): 客观存在并可相互区分的事物。例如,“学生张三”、“课程C01”都是实体。
实体型 (Entity Type): 对某一类实体的抽象描述,用实体名及其属性名集合来刻画。例如,“学生”就是一个实体型,它具有学号、姓名、专业等属性。
属性 (Attribute): 实体所具有的某一特性。例如,“姓名”就是“学生”实体型的一个属性。
码 (Key): 唯一标识实体的属性或属性集。例如,“学号”是学生实体型的码。
联系 (Relation): 描述实体型之间的关联关系。联系本身也可以有属性。例如,学生和课程之间存在“选修”的联系,“选修”这个联系可以有“成绩”这个属性。
一对一联系 (1:1): 例如,一个班级只有一个班长,一个班长只属于一个班级。
一对多联系 (1:n): 例如,一个班级有多名学生,但一名学生只属于一个班级。
多对多联系 (m:n): 例如,一名学生可以选修多门课程,一门课程也可以被多名学生选修。
2. E-R图 (E-R Diagram)
E-R图是展示概念模型的直观工具,有固定的图示约定:
实体型: 用 矩形 表示。
属性: 用 椭圆形 表示。
联系: 用 菱形 表示。

三、 数据模型的三要素
一个完整的数据模型,无论其具体类型(关系、网状等),都必须包含以下三个核心要素:
1. 数据结构
定义: 描述数据的静态特性,即数据库的组成对象以及对象之间的联系。
作用: 这是数据模型的基础,刻画了数据的组织形式。我们通常根据数据结构的类型来为数据模型命名。
示例: 在 关系模型 中,数据结构就是规范化的 二维表(关系),数据都以行和列的形式组织。
2. 数据操作
定义: 描述数据的动态特性,即对数据库中各种对象实例允许执行的操作集合,以及相关的操作规则。
作用: 定义了可以对数据做什么。
分类: 主要分为两大类:
检索: 查询数据(如 SQL 中的 SELECT)。
更新: 插入、删除、修改数据(如 INSERT, DELETE, UPDATE)。
3. 完整性约束
定义: 一组完整性规则的集合。这些规则是数据及其联系所必须满足的制约和依存条件,用以保证数据的正确、有效和相容。
作用: 是数据库的“法律”,防止不合规的数据进入系统。
示例:
学生的年龄必须是大于0的整数。
每个学生的学号必须是唯一的(实体完整性)。
学生选课记录中的课程号,必须是课程表中已存在的课程号(参照完整性)。
四、 经典数据模型的分类
历史上,根据 数据结构(即数据之间联系的表示方式)的不同,主要出现了三种经典的数据模型:
1. 层次模型
数据结构: 用 树形结构(有向树) 来表示数据间的联系。
特点:
结构简单,易于实现。
只能直接表示 一对多 (1:n) 的联系。
数据访问必须从根节点开始,路径单一,不方便。
2. 网状模型
数据结构: 用 图结构(有向图) 来表示数据间的联系。
特点:
可以表示实体间更复杂的联系,包括 多对多 (m:n) 关系。
相比层次模型,结构更复杂,程序设计也更复杂。
3. 关系模型
数据结构: 用 二维表格结构(关系) 来表示实体及实体间的联系。
特点:
概念单一,结构简单: 无论是实体还是实体间的联系,都用统一的“表”来表示,非常直观。
理论基础坚实: 建立在严格的数学概念(集合论和谓词逻辑)之上。
关系模型已经成为当今数据库产品的主流。
数据库系统体系结构
为了实现之前提到的 “数据独立性”,数据库系统在结构上采用了精巧的分层设计,即三级模式结构。
三级模式
模式,也称概念模式
视角: 数据库的全局、核心视角。
描述内容: 描述了 整个数据库 的逻辑结构和特征。它定义了所有的实体、属性、它们之间的关系,以及数据的完整性、安全性约束。
特点:
是数据库的中心和枢纽,是所有用户(包括应用程序和数据库管理员DBA)的公共数据视图。
一个数据库 只有一个 模式。
它独立于具体的应用程序和物理存储细节。
谁使用: 主要由数据库管理员(DBA)负责设计和维护。
外模式,也称子模式或用户视图
视角: 某个特定应用程序或用户的局部视角。
描述内容: 描述了某个特定用户或应用 所能看到和使用的那部分数据 的逻辑结构。
特点:
是模式的一个子集。
一个数据库可以有 多个 外模式,不同的外模式可以相互重叠。
简化了用户接口,并提供了安全保障(用户只能看到他们被授权看到的数据)。
谁使用: 应用程序员和最终用户。
内模式,也称存储模式
视角: 数据库的物理存储视角。
描述内容: 描述了数据在物理存储介质上的 存储方式和物理结构。例如,数据以何种文件形式组织、索引如何创建、数据是否压缩等。
特点:
是三级模式中最低层、最接近硬件的一层。
一个数据库 只有一个 内模式。
负责将逻辑数据结构映射到实际的物理存储上。
谁使用: 由DBMS本身和DBA管理。
两级映像
为了将这三个独立的层次关联起来,并实现它们之间的解耦,DBMS提供了两个关键的“转换层”或“映射层”:
外模式/模式映像
作用: 定义了某个外模式与概念模式之间的对应关系。
实现的功能: 逻辑独立性。当数据库的整体逻辑结构(模式)发生改变时(例如,为一张表增加一个新列),只要这个改变不影响某个外模式,DBA就可以通过修改这个映像,使得对应的应用程序完全感知不到变化,无需重写。
模式/内模式映像
作用: 定义了概念模式与内模式之间的对应关系。
实现的功能: 物理独立性。当数据库的物理存储结构(内模式)发生改变时(例如,为了提升性能而增加了一个索引,或更换了存储设备),DBA只需修改这个映像,就能保证上层的模式和所有外模式保持不变。因此,所有应用程序都无需修改。
DBMS的主要功能
数据库定义功能
DBMS提供 数据定义语言 (DDL),允许用户(主要是DBA)定义数据库的三级模式、完整性约束、权限等。这些定义信息被编译后存储在 数据字典 中。
数据存取功能
DBMS提供 数据操纵语言 (DML),允许用户和应用程序对数据库进行查询、插入、修改和删除操作。这是用户与数据库交互的主要方式。
数据库运行管理
并发控制: 协调多个用户的同时操作,防止数据冲突和不一致。
安全性控制: 进行用户身份验证和权限检查,防止未经授权的访问。
完整性控制: 检查所有插入和修改操作是否符合预设的完整性规则。
事务管理和恢复: 保证一组操作(事务)的原子性,并在系统发生故障时,有能力将数据库恢复到一致状态。
数据库的建立和维护功能
提供一系列实用工具程序,用于数据库的日常管理和维护,如:数据导入/导出、数据库备份与恢复、性能监控与分析等。
数据库管理员 (DBA - Database Administrator)
DBA是一个 人 的角色,其主要职责包括:
建库方面
决定数据库中的信息内容和结构(设计概念模式和外模式)。
设计数据库的物理存储结构和存取策略(设计内模式)。
负责数据的初始装入和系统的建立。
用库方面
定义数据的安全性和完整性规则。
管理用户权限,监控用户对数据库的访问。
制定和执行数据库的备份和恢复策略。
改进方面
监控数据库系统的运行性能,分析瓶颈。
进行数据库的重组织和重构造,以提高性能和适应新的需求。
补充说明
1. 为什么文件系统的“程序-数据独立性”是有限的?
简单来说,独立性有限是因为 应用程序必须非常清楚地知道它所读取的文件的物理和逻辑结构。程序和数据文件就像是两片拼图,必须严丝合缝才能工作,换掉其中一片的形状,另一片就必须跟着改变。
这种依赖性主要体现在两个层面:
A. 逻辑结构依赖
应用程序的代码直接依赖于文件中数据的 组织方式和顺序。
例子: 假设你有一个 student.txt 文件,每行存储一个学生的信息,格式为:学号(10个字符), 姓名(20个字符), 专业(30个字符)。
你的程序会这样写(伪代码):
// 打开 student.txt 文件 读取前10个字符,存入 “学号” 变量 读取接下来的20个字符,存入 “姓名” 变量 读取最后的30个字符,存入 “专业” 变量问题来了: 如果业务需求变更,需要在“姓名”和“专业”之间增加一个“入学年份(4个字符)”字段。现在 student.txt 的格式变成了:学号(10), 姓名(20), 入学年份(4), 专业(30)。
后果: 原来的程序就彻底崩坏了。它会把“入学年份”的前20个字符(如果后面还有数据的话)当成“专业”来读取,导致数据错乱。为了适应这个变化,你必须找到所有读取 student.txt 文件的程序,修改它们的读取逻辑。这就是 逻辑结构依赖 —— 程序的逻辑和文件的逻辑结构紧紧地绑定在一起。
B. 物理结构依赖
应用程序的代码还可能依赖于数据的 存储方式和物理特性(如数据类型、长度等)。
例子: 继续上面的例子,假设学校决定将“学号”从10个字符升级为12个字符。
后果: 你的程序中为“学号”变量分配的内存空间可能只有10个字符,现在读取12个字符就会导致 内存溢出 或数据截断。你同样需要修改所有相关程序的代码,调整变量的存储空间。这就是 物理结构依赖。
总结: 在文件系统阶段,数据文件本身只是被动地存储数据。所有关于“这个数据是什么意思”、“它在哪里”、“它有多长”的解释权和处理逻辑,都分散在每一个应用程序中。因此,只要数据文件的结构(无论是逻辑上增加字段,还是物理上改变长度)发生任何变化,所有依赖它的应用程序都必须进行修改,这使得系统维护起来极其困难和昂贵。
2. “集成的” 和 “共享的 ” 是什么意思?
这两个概念是数据库系统的核心思想,下面通过一个例子来对比文件系统进行理解。
场景:一所大学的学生信息管理
假设大学有三个部门都需要学生信息:
招生办公室: 关心学生的申请材料、姓名、家庭住址。
教务处: 关心学生的学号、姓名、所选课程、成绩。
财务处: 关心学生的姓名、家庭住址(用于寄账单)、学费缴纳情况。
在文件系统阶段(非集成、伪共享)
每个部门都会为自己的应用建立独立的数据文件:
招生办有一个 admissions.dat 文件,内容:[申请号, 姓名, 家庭住址, ...]
教务处有一个 registrar.dat 文件,内容:[学号, 姓名, 选课信息, ...]
财务处有一个 finance.dat 文件,内容:[学号, 姓名, 家庭住址, 应缴学费, ...]
问题显而易见:
数据冗余: "姓名" 和 "家庭住址" 这些信息在多个文件中重复存储。这不仅浪费存储空间,更是导致不一致的根源。
数据不一致: 如果一个学生搬家了,他去财务处更新了地址。但如果财务处没有通知其他两个部门,那么现在学校的系统里就有了这个学生的两个不同地址(一个旧的,一个新的),导致数据混乱。
数据孤岛: 数据被隔离在各自的应用中。教务处想知道某个学生的家庭住址,可能需要通过复杂的流程去读取财务处的文件,非常不便。
在数据库系统阶段(集成的、共享的)
现在,我们不再创建多个独立的文件,而是创建一个统一的 学生数据库。
第一步:实现“集成”
“集成”就是将那些分散、重复的数据整合起来,消除冗余,形成一个逻辑上统一的整体。
在学生数据库里,我们会设计一个 学生表。
这张表里包含了 [学号, 姓名, 家庭住址, 专业, ...] 等字段。
关键在于,任何一个学生的核心信息(如姓名、住址)在整个数据库中只存储一次。
这就解决了数据冗余和不一致的问题。如果学生搬家了,只需更新 学生表 中唯一的那条记录,所有访问该记录的应用都能立刻看到最新的正确地址。
集成的本质: 将数据从“为某个应用服务”转变为“为整个组织服务”,建立“单一数据源”。
第二步:实现“共享”
“共享”指的是,这个集成的、统一的数据库可以被多个用户、多个应用程序,在同一时间、从不同地点访问。
现在,招生办、教务处、财务处的应用程序不再访问各自的 .dat 文件,而是 同时连接到同一个学生数据库。
数据库管理系统 (DBMS) 就像一个严格的图书管理员,负责管理这个共享过程:
教务处 的应用可以查询和修改 学生表 中的成绩信息。
财务处 的应用可以查询 学生表 中的地址信息,并更新缴费状态。
DBMS会确保当财务处正在修改某个学生的缴费记录时,教务处的应用不会同时删除这个学生,从而保证了数据的一致性和完整性。
共享的本质: 数据不再属于任何一个单一的应用,而是成为一种公共资源,由DBMS统一协调和管理,按需提供给所有有权限的应用。
总结一下关系:
集成是共享的基础。 你必须先把分散的数据整合起来,消除冗余和矛盾(集成),然后才能安全、高效地让大家一起使用(共享)。数据库系统通过“集成”和“共享”这两个核心特性,完美地解决了文件系统阶段的各种弊端。
3. 以下 E-R 图中的 1、n、m 是什么意思?

简单来说,它们定义了“谁和谁可以有多少个关联”。
1 代表 “一”:表示一个实体实例只能与另一个实体的一个实例相关联。
n 代表 “多”:表示一个实体实例可以与另一个实体的零个、一个或多个实例相关联。
m 也代表 “多”:当一个联系中需要表示两个不同的“多”时,就用 m 和 n 来区分,例如在“多对多”关系中。
让我们结合图中的三个例子来理解:
图 (a): 同一实体内的联系
这个例子展示了“职工”这个实体内部的“领导”关系。
一个职工(作为领导)可以领导 多 (n) 个职工。
一个职工(作为下属)只被 一 (1) 个领导所领导。
所以,这是一个 一对多 (1:n) 的关系,描述了典型的公司层级结构。
图 (b): 三个实体间的联系
这个例子展示了“教师”、“课程”和“参考书”三个实体通过“讲授”这个动作联系起来。
一个教师可以讲授 多 (m) 门课程。
一门课程可以被 多 (m) 个教师讲授 (这里 m 同时描述了教师和课程都是“多”的关系)。
一门课程会用到 多 (n)本参考书。
综合来看,这描述了一个复杂的多对多对多关系:多 (m) 个教师,讲授 一 (1) 门课程,会用到 多 (n) 本参考书。
图 (c): 两个实体间的多种联系
这个例子展示了“工人”和“机器”之间可以存在不止一种关系。
“使用”关系:
一个工人可以使用 多 (n) 台机器。
一台机器也可以被 多 (m) 个工人使用。
因此,“使用”是一个 多对多 (m:n) 的关系。
“维修”关系:
一个工人负责维修 多 (n) 台机器。
一台机器只由 一 (1) 个工人负责维修。
因此,“维修”是一个 一对多 (1:n) 的关系。
4. E-R 图实体之间联系的语义扩充

(1) 存在依赖 - 弱实体
是什么意思?
一个实体(称为 弱实体)的存在,必须依赖于另一个实体(称为 强实体)的存在。如果那个强实体被删除了,那么与之关联的弱实体也必须被删除。图例解释: “子女”实体的存在依赖于“职工”实体的存在。一个子女的信息只有在关联到某个职工时才有意义。如果一个职工离职,其档案被删除,那么他/她的子女信息也应该一并被删除。因此,“子女”是一个弱实体。
为什么重要?
它定义了一种强制性的“父-子”关系。在数据库设计中,这意味着:主键问题: 弱实体(子女)的主键通常需要包含其父实体(职工)的主键的一部分,形成一个复合主键。例如,子女的主键可能是 (职工号, 子女姓名)。
数据完整性: 保证了不会有“孤儿”数据存在。你不能在系统中添加一个子女,却不指定他/她是谁的孩子。这通过数据库的“外键约束”和“级联删除”等功能来实现。
(2) 标识依赖
是什么意思?
这通常与弱实体相关。它指的是一个弱实体不能仅靠自己的属性来唯一标识自己,必须依赖其关联的强实体的标识符(主键) 才能被唯一确定。图例解释: “学生”实体依赖于“学校”实体来标识。可能很多学校都有一个学号为 S001 的学生,但只有 (学校代码, 学号) 这个组合才是全局唯一的。所以,学生实体的唯一标识依赖于学校实体。
为什么重要?
它明确了实体之间的主键依赖关系。这直接指导了数据库表结构的设计,特别是复合主鍵的创建,确保了每一条记录在全局范围内的唯一性。
(3) 实体的子类 - 泛化与特殊化
是什么意思?
这是一种用来表示 “is-a” (是一种)关系的模型。一个通用的实体类型(父类,或称 超类),可以有多个更具体的实体类型(子类)。图例解释: “教师”、“实验员”和“行政人员”都是“教职工”的一种。
泛化: 从教师、实验员、行政人员中抽出共同属性(姓名、性别、年龄),形成一个更通用的“教职工”实体。
特殊化
: “教职工”这个通用实体,可以根据职业类型,特殊化为教师、实验员等子类。
为什么重要?
这在面向对象设计中非常常见,对数据库设计同样至关重要:属性继承: 子类(如教师)会自动继承父类(教职工)的所有属性(姓名、年龄等)。
减少冗余: 你不需要在教师、实验员、行政人员三个表中都重复定义“姓名、性别、年龄”这些列。
结构清晰: 允许子类拥有自己独特的属性。例如,“教师”可以有“职称”属性,“实验员”可以有“实验室编号”属性,而这些属性对于其他子类是没有意义的。这使得数据模型非常清晰,且易于扩展。
5. 为什么说关系模型建立在严格的数学概念之上?
当IBM的数学家 E. F. Codd 提出关系模型时,当时已有的数据库系统(层次模型和网状模型)都非常复杂。程序员必须编写代码,像跟着地图一样,在数据记录之间手动导航。Codd 希望引入数学的严谨性,来让数据管理变得更简单、更强大,并且独立于物理存储的细节。
他主要运用了数学的两个分支:
A. 集合论:结构的基础
B. 谓词逻辑:查询的基础
详见第二章。
6. 为什么要求关系中每个分量是 “不可分的数据项” ?
这个规则,即 第一范式 (First Normal Form, 1NF),是上述数学基础的直接且必然的推论。“不可分”或“原子性”意味着 表中每个单元格必须只包含一个单一的值,而不能是一个列表或一组值。
让我们用一个“坏”的(非原子性的)例子来说明它为什么会破坏一切。
坏例子 (违反第一范式):
在这里电话号码 这一列就不是原子的。小红的单元格里包含了一个由两个号码组成的列表。这种看似方便的结构,在实际中会造成噩梦:
它破坏了查询: 你如何查找电话号码是
555-8888的所有学生?你不能写WHERE 电话号码 = '555-8888'。你将不得不依赖缓慢且不可靠的字符串搜索LIKE '%555-8888%'),这种方式效率低下且容易出错。如果有人用分号而不是逗号输入号码怎么办?它破坏了唯一性和键: 主键
学号能唯一标识一行,但如果你想唯一标识一个特定的电话号码呢?你做不到。非原子单元格内部的值没有自己独立的身份。它破坏了数学模型: 关系代数的操作(如选择、投影、连接)是定义在简单、单一的值上的。它们不知道如何处理单元格内部的列表。整个模型的逻辑和数学一致性就崩溃了。
正确的 (原子性的) 解决方案
为了修正这个问题,你需要遵循关系模型的原则来建模。因为一个学生可以有 多个 电话号码,所以你应该创建一个独立的表来表示这种“多”的关系。
学生表:
学生电话表:
现在,每个单元格都只包含一个单一的、原子的值。这样做的好处显而易见:
查询简单: 查找
555-8888的拥有者,只需SELECT 学号 FROM 学生电话表 WHERE 电话号码 = '555-8888'。唯一性清晰:
学生电话表的主键将是(学号, 电话号码)的组合。模型一致: 两张表都遵循了“关系”的定义,所有的关系运算都可以正确、高效地应用。
总结来说,对原子性的要求不是一个随意的规定,它是将集合论和谓词逻辑应用于数据管理的必前提。
7. DBMS的组成
语言编译处理程序
系统运行控制程序
包括系统总控、存取控制、并发控制、完整性控制、保密性控制、数据存取和更新、通信控制等程序。
系统建立和维护程序
数据装入、数据库系统恢复、性能监督、工作日志等程序。
数据字典
也称为数据目录或系统目录,由一系列表组成,存储着数据库中有关信息的当前描述,包括数据库的三级模式、用户名表、用户权限等信息。
第二章 关系数据库
关系模型的基本概念
一、 关系模型的数学定义与核心术语
域
定义:域是一组具有相同数据类型的值的集合。
示例:整数集合、所有字符串的集合、一个特定的枚举集合如 {男, 女} 或 {CS, MA, IS}。
作用:域规定了数据表中某一列(属性)的取值范围。
笛卡尔积
定义:给定一组域 D₁, D₂, ..., Dₙ,它们的笛卡尔积 D₁ × D₂ × ... × Dₙ 是所有可能元组 (d₁, d₂, ..., dₙ) 的集合,其中每个分量 dᵢ 来自于其对应的域 Dᵢ。
笛卡尔积可以形象地理解为一个由所有域的值的所有可能组合构成的“超级大表”。
元组 与 分量
元组:笛卡尔积中的每一个元素 (d₁, d₂, ..., dₙ) 称为一个n-元组,或简称元组。在数据库中,这对应于二维表中的一行数据。
分量:元组中的每一个值 dᵢ 称为一个分量。这对应于表中的一个单元格数据。
关系
定义:关系是笛卡尔积 D₁ × D₂ × ... × Dₙ 的一个有限子集。
解释:在数据库中,我们通常不关心所有可能的元组组合(整个笛卡尔积),而只关心那些有意义的、实际存在的组合。这些有意义的元组构成的集合就是一个关系。
表示:关系通常用一个二维表来表示,表名即关系名。
属性
定义:在关系模型中,二维表的每一列被称为一个属性。每个属性都有一个唯一的名称,即属性名。
作用:属性的引入消除了列的有序性。因为我们可以通过属性名来唯一指定一列,而无需关心它在表中的物理位置。
二、 关系数据结构
关系模型的核心数据结构就是“关系”,它用来统一表示现实世界中的实体以及实体间的联系。
关系模式
定义:关系模式是对关系的描述,是静态的、稳定的。它定义了关系的结构。
形式化表示:R (U, D, dom, F)
R:关系名
U:组成该关系的属性名集合
D:属性所来自的域的集合
dom:属性到域的映射集合
F:属性间的数据依赖关系集合
示例:
假设有关系模式 学生 (学号, 姓名, 系别)R (关系名): 学生
U (属性集合): {学号, 姓名, 系别}
D (域集合): {学号域, 姓名域, 系别域},其中 学号域 可能是所有6位数字字符串的集合,姓名域 是所有字符串的集合,系别域 是 {CS, MA, IS} 这样的集合。
dom (映射): dom(学号) = 学号域,dom(姓名) = 姓名域,dom(系别) = 系别域。它指明了每个属性的取值范围。
F (数据依赖): {学号 → (姓名, 系别)},这表示“学号”这个属性的值可以唯一确定“姓名”和“系别”的值,这是主码依赖。
简化表示:在实际应用中,我们通常简记为 R (属性名1, 属性名2, ..., 属性名n)。例如:学生 (学号, 姓名, 年龄, 系别)。
关系实例
定义:关系实例是关系模式在某一时刻的状态或内容,即二维表中的具体数据。它是动态的、随时间变化的。我们通常所说的“关系”或“表”实际上指的是关系实例。
码 (Key)
作用:用于在关系中唯一地标识一个元组(行)。
候选码:关系中的一个属性或属性组,它的值能够唯一地标识一个元组,并且其任何真子集都不能唯一标识元组(最小性)。
主码:如果一个关系有多个候选码,则选定其中一个作为主码。
主属性:包含在任何候选码中的属性。
非主属性:不包含在任何候选码中的属性。
三、 关系的性质
一个规范的关系(满足第一范式 1NF 的关系)必须具备以下性质:
列的同质性:每一列中的分量都来自同一个域,数据类型相同。
属性名的唯一性:不同的列可以出自同一个域,但必须有不同的属性名。
列的顺序无关性:列的物理顺序可以任意交换,不影响关系表达的信息。(因为每一列都由唯一的属性名标识,而不是通过其物理位置,比如关系 (学号, 姓名) 和 (姓名, 学号) 表达的是完全相同的信息。)
行的顺序无关性:行的物理顺序可以任意交换,因为关系是元组的集合,集合内元素无序。
元组的唯一性:关系中任意两个元组不能完全相同,这是由“集合”的互异性决定的。
分量的原子性:每一个分量必须是不可再分的原子数据项。这是关系模型最基本的要求,满足此条即为第一范式 (1NF)。
四、 关系模型的完整性约束
为了保证数据库中数据的正确性、有效性和相容性,关系模型定义了三类必须支持的完整性约束。
实体完整性
规则:关系的主码值不能为空 (NULL) 或部分为空。
目的:保证关系中的每一个元组都是可唯一标识、真实存在的实体。
参照完整性
核心概念:外码。关系R中的一个属性(或属性组)F,它不是R的主码,但与另一关系S的主码Ks相对应,则称F为R的外码。(注:S和R可以是同一个关系)
规则:外码的取值必须是其参照关系(S)中某个主码的值,或者为空 (NULL)。
目的:维持表与表之间的关联关系,防止出现引用不存在的实体的情况。
用户定义完整性
定义:针对具体应用环境定义的约束条件。例如,学生年龄必须在0到150之间,成绩必须在0到100之间等。
目的:确保数据符合具体的业务逻辑和现实世界的规则。
五、 关系模型的数据操作
一个完整的数据模型不仅包括数据结构和完整性约束,还包括数据操作。
特点:关系数据操作是集合操作,即“一次一集合”。操作的对象是一个或多个关系(集合),操作的结果也是一个新的关系(集合)。
关系运算:关系运算是关系数据操作的基础,主要分为两种:
关系代数:一种过程化的查询语言。它通过一系列关系代数运算符(如选择、投影、并、差、连接等)逐步对关系进行运算,最终得到查询结果。它定义了“如何做”。
关系演算:一种非过程化的查询语言,基于谓词逻辑,它只需用户声明“做什么”(想要得到什么结果),而无需指明具体的执行步骤。它分为元组关系演算和域关系演算。
三种关系运算互相等价,可转换。
关系代数
关系代数运算按其性质可分为两类:
传统集合运算
专门的关系运算
一、 传统集合运算
这类运算源自数学中的集合论,但在应用于关系时,有一个重要的前提条件。
前提条件:并相容性(同类关系)
除笛卡尔积外,参与传统集合运算的两个关系(例如R和S)必须是并相容的。
定义:
两个关系具有相同的度,即属性(列)的数量相同。
两个关系对应属性的域相同,即对应列的数据类型和取值范围相同。
并
符号:∪
定义:关系R和关系S的并,记为 R ∪ S,结果是由所有属于R或属于S的元组构成的新关系。运算会自动去除重复的元组。
形式化:R ∪ S = { t | t ∈ R ∨ t ∈ S }
差
符号:-
定义:关系R和关系S的差,记为 R - S,结果是由所有属于R但不属于S的元组构成的新关系。
形式化:R - S = { t | t ∈ R ∧ t ∉ S }
交
符号:∩
定义:关系R和关系S的交,记为 R ∩ S,结果是由既属于R又属于S的元组构成的新关系。
形式化:R ∩ S = { t | t ∈ R ∧ t ∈ S }
广义笛卡尔积
符号:×
定义:关系R(度为n)和关系S(度为m)的广义笛卡尔积,记为 R × S,结果是一个度为 (n+m) 的新关系。新关系的每个元组由R中的一个元组与S中的一个元组串接(这里与传统的笛卡尔积不同)而成。
注意:此运算不要求关系是并相容的。
二、 专门的关系运算
关系代数中特有的的运算,便于数据库查询操作。
选择
符号:σ
作用:从关系中筛选出满足指定条件的元组(行)。这是一种“水平”方向的筛选。
表示:σ_F(R)
R:要操作的关系。
F:选择条件,是一个逻辑表达式,由属性名、常量、比较运算符(>, <, =, ≠ 等)和逻辑运算符(∧, ∨, ¬)组成。
示例:从学生表(S)中检索出所有计算机科学系(CS)的学生(学生所在系为SD列)。σ_{SD='CS'}(S)
投影
符号: Π
作用:从关系中选择出指定的属性(列)来组成一个新的关系。这是一种“垂直”方向的筛选。
重要特性:投影运算会自动删除结果中重复的行,以保证结果仍然是一个合法的关系(集合)。
表示:Π_A(R)
R:要操作的关系。
A:要保留的属性名列表。
示例:查询所有学生的姓名(SN)和所在系(SD)。Π_{SN, SD}(S)
连接
符号:⋈
作用:根据指定的连接条件,将两个关系合并成一个更宽的新关系。
通用形式 (θ-连接):R \underset{X\theta Y}{\bowtie} S
其本质是先计算 R × S 的笛卡尔积,然后根据条件 XθY 对结果进行选择运算。
X 和 Y 分别是 R和 S上的属性组(要求包含同等数量的属性,且相应(不需要相同)的属性具有共同的域),θ 是比较运算符。
等值连接:当 θ 为 = 时,称为等值连接。这是最常用的一种连接方式。
自然连接
符号:⋈ (与连接符号相同,但通常不带条件)
作用:是一种特殊的等值连接,它要求两个关系具有一个或多个同名的公共属性。
运算过程:
在两个关系的公共属性上进行等值连接(即要求公共属性的值相等)。
在结果中去掉重复的公共属性列。
与等值连接的区别:自然连接自动处理公共属性的匹配和去重,更为简洁和常用。
除法
符号:÷
作用:通常用于解决包含“全部”或“所有”这类词语的查询需求。
定义:设关系 R(X, Y) 和 S(Y),R ÷ S 的结果是一个只包含属性 X 的关系。结果中的每个元组 x 必须满足:对于 S 中的每一个元组 y,都存在一个元组 (x, y) 在 R 中。
关系演算
关系演算是基于谓词逻辑的查询语言。与关系代数不同,它不关心具体的操作步骤,而是通过描述结果所需满足的条件来定义查询。
两种形式:
元组关系演算:以元组作为变量的基本单位。
域关系演算:以域变量(即属性值)作为变量的基本单位。
一、 元组关系演算
运算的基本单位是元组变量。我们用一个变量(如 t, u)来表示一个完整的元组(即表中的一行)。
表达式基本结构是: { t | Φ(t) }
t:一个元组变量。它代表我们想要查询结果中的每一行。
|:意为“满足条件”。
Φ(t):一个公式,它定义了元组 t 必须满足的逻辑条件。只有使 Φ(t) 为真的元组 t 才能成为结果的一部分。
通俗理解:“给出所有满足条件 Φ 的元组 t 的集合”。
公式 Φ 是由更小的构件——原子公式——通过逻辑运算符组合而成的。
三类原子公式:
R(t):表示“元组 t 存在于关系 R 中”。这是用来指定变量 t 的来源表。
t[i] θ u[j]:表示“元组 t 的第 i 个分量(属性值)与元组 u 的第 j 个分量之间满足比较关系 θ”。(θ 可以是 >、<、= 等)。
t[i] θ c:表示“元组 t 的第 i 个分量与一个常量 c 之间满足比较关系 θ”。
构建更复杂的公式:
逻辑连接词:可以使用 ∧ (与)、∨ (或)、¬ (非) 来组合原子公式。
量词:
存在量词 ∃:∃t(Φ(t)) 表示存在至少一个元组 t 使得 Φ(t) 为真。
全称量词 ∀:∀t(Φ(t)) 表示对于所有的元组 t,Φ(t) 都为真。
被量词修饰的元组变量成为约束元组变量,否则为自由元组变量。
例:查询计算机系(CS)的全体学生。
关系代数:σ_SD='CS'(S)
元组关系演算:{ t | S(t) ∧ t[4] = 'CS' }
二、 域关系演算
运算的基本单位是域变量。我们用变量(如 x, y, z)来表示单个的属性值(即单元格中的值),而不是表示一整行。
表达式基本结构是: { (x₁, x₂, ..., xₖ) | Φ(x₁, x₂, ..., xₖ) }
(x₁, x₂, ..., xₖ):这是一组域变量。它定义了我们想要的结果表的列。
| 与 Φ:同元组关系演算。
通俗理解:“给出所有满足条件 Φ 的域变量组合 (x₁, x₂, ..., xₖ) 的集合”。
三类原子公式:
R(x₁, x₂, ..., xₙ):表示“域变量的组合 (x₁, ..., xₙ) 是关系 R 中的一个元组(一行)”。
xᵢ θ c:表示“域变量 xᵢ 与常量 c 满足比较关系 θ”。
xᵢ θ xⱼ:表示“域变量 xᵢ 与域变量 xⱼ 满足比较关系 θ”。
构建方式:与元组关系演算相同,也使用逻辑连接词和量词来构建复杂公式。
例:查询计算机系(CS)的全体学生。
元组关系演算:{ t | S(t) ∧ t[4] = 'CS' }
域关系演算:{ (sno, sname, sage, sdept) | S(sno, sname, sage, sdept) ∧ sdept = 'CS' }
{ (sno, sname, sage, sdept) | ... }:一个由四个域变量(分别代表学号、姓名、年龄、系别)构成的元组的集合。
三、 关系演算的安全约束与等价性
关系演算的一个理论问题是可能写出产生无限结果的表达式。例如,{ t | ¬S(t) } 的意思是“查询所有不存在于学生表 S 中的元组”,这在理论上是无限的。
为了解决这个问题,引入了安全约束:要求表达式中涉及的所有值都必须来自于数据库中实际存在的域(称为 DOM(Φ))。简单来说,查询不能超出数据库当前已有值的范围。经过安全约束的关系演算称为安全的关系演算。
关系代数、安全元组关系演算、安全域关系演算,这三者的表达能力是等价的。
这意味着,任何一种方式表达的查询,也一定可以用另外两种方式来表达。
关系数据语言概述
一、 数据库数据语言
数据库数据语言是用户与数据库管理系统 (DBMS) 交互的接口。从功能上,它通常被划分为以下三种类型:
数据定义语言 (Data Definition Language, DDL)
作用:用于定义和管理数据库的结构。它不是用来操作具体数据的。
功能:创建 (CREATE)、修改 (ALTER)、删除 (DROP) 数据库对象,如数据库、表、视图、索引等。
示例:CREATE TABLE Student (...)
数据操纵语言
作用:用于对数据库中的数据进行操作。
四大基本操作:
检索 (SELECT):查询数据。
插入 (INSERT):添加新数据。
修改 (UPDATE):更新已有数据。
删除 (DELETE):移除数据。
使用方式:
交互式DML (自含式语言):用户可以直接在终端输入命令并立即看到结果,适用于临时查询和数据管理。
嵌入式DML (宿主语言):将DML语句嵌入到高级编程语言(如Java, Python, C++)中,用于开发应用程序。
数据控制语言
作用:用于管理数据库的访问权限和安全控制。
功能:
授权 (GRANT):授予用户或角色特定的操作权限。
收回权限 (REVOKE):取消已经授予的权限。
还包括事务控制(如 COMMIT, ROLLBACK)和并发控制等。
二、 关系数据语言的特点
关系数据语言(如SQL)之所以能成为主流,是因为它具备许多优越的特性:
一体化
它将 DDL、DML、DCL 的功能高度集成在一种语言中。用户无需学习多种语言,用一套统一的语法就可以完成数据库的定义、操纵和控制,极大地简化了学习和使用。
非过程化
用户只需声明“做什么”,而无需指明“怎么做”。例如,用户只需写出 SELECT * FROM Student WHERE SD = 'CS',DBMS会自动规划最优的查询路径(是先扫描全表还是使用索引)。这大大降低了用户的使用门槛。
面向集合的存取方式
关系数据语言的操作对象和操作结果都是集合(关系/表)。它可以“一次一集合”地处理数据,而不是像传统编程语言那样需要用循环一条一条地处理记录,效率更高,代码也更简洁。
既可独立使用,又可嵌入使用
它既可以作为独立的查询语言(交互式),也可以嵌入到高级语言中(嵌入式),提供了极大的灵活性。
三、 关系数据语言的分类
关系运算是设计关系数据语言的基础,关系运算的分类也决定了关系语言的分类。

ISBL (Information System Base Language):早期关系代数语言的代表,主要用于研究和实验系统。
QUEL (Query Language):早期关系数据库系统 Ingres 使用的查询语言,基于元组演算。
QBE (Query By Example):通过填写示例表格的方式进行查询,非常直观,适合初学者。
SQL (Structured Query Language):最初由IBM开发,后来成为国际标准。它吸收了各种理论的优点,取得了巨大的商业成功,是目前应用最广泛的关系数据语言。
四、 关系模型的优缺点总结
优点:
坚实的理论基础:建立在严格的数学概念之上,使得模型严谨、规范。
概念单一,结构简单:所有实体和实体间的联系都用统一的“关系”(二维表)来表示,查询结果也是关系,非常直观易懂。
高度的数据独立性:存取路径对用户透明,用户无需关心数据在物理上如何存储和访问,简化了开发和维护工作。
强大的查询能力:非过程化的语言(如SQL)使得复杂的查询能够用简洁的语句来表达。
缺点:
查询效率问题:由于存取路径对用户透明,系统需要进行复杂的查询优化来找到高效的执行路径。在某些复杂查询场景下,其性能可能不如导航式的层次或网状模型。
开发难度:为了实现查询优化、并发控制、事务管理等高级功能,关系数据库管理系统(RDBMS)的开发和实现非常复杂。
补充说明
1. 关系代数举例
连接与自然连接


除法
除法用于解决“查询满足全部条件”的问题。比如下图上半部分意为“求选修了全部课程的学生的学号”。

下半部分答案为空集。比如对于(95001, 92):
为了让 (95001, 92) 出现在结果中,以下三行数据必须全部存在于左侧表中:
(95001, C1, 92) — 存在。
(95001, C2, 92) — 不存在 (实际是 ...C2, 85)。
(95001, C3, 92) — 不存在 (实际是 ...C3, 88)。
(95001, 92) 不满足条件。
综合举例


2. 关系演算举例
元组关系演算

域关系演算

关系运算等价性举例
以关系代数和元组关系演算为例:

3.关系运算的安全约束示例
示例:一个不安全的查询
假设我们有一个简单的学生表 S:
现在,考虑一个用元组关系演算写出的查询:
查询:找出所有不是我们学校学生的人。
表达式:{ t | ¬S(t) }
{ t | ... }:我们想要一个元组 t 的集合。
¬S(t):条件是,元组 t 不在 S 表中。
这个查询为什么不安全?
('S3', 'Charlie', 21) 不在 S 表中,所以它满足条件。
('S4', 'David', 25) 也不在 S 表中,也满足条件。
('P1', 'ProductA', 99.9) 这个元组和学生毫无关系,但它确实也不在 S 表中,所以它也满足条件。
('任何可能的字符串', '任何可能的字符串', 任何可能的数字) 的组合有无限多个,只要它们不恰好等于 ('S1', 'Alice', 20) 或 ('S2', 'Bob', 22),它们就都满足条件。
因此,这个查询的结果集是无限的,数据库系统无法计算并返回这个结果。这就是一个典型的不安全查询。
DOM(Φ) 的引入与安全约束
为了解决这个问题,我们引入了“安全约束”的概念。其核心思想是:
一个查询是安全的,当且仅当该查询结果中的所有值,都必须来自于数据库中已经存在的值的集合。
这个“数据库中已经存在的值的集合”就是 DOM(Φ)。
DOM(Φ) (Domain of Formula Φ) 的定义:
DOM(Φ) 是一个有限的集合,由以下两部分构成:
公式 Φ 中出现的所有常量。
出现在 Φ 所引用的关系(表)中的所有值。
对于我们上面的学生表示例:
关系 S 中出现的所有值是:{'S1', 'Alice', 20, 'S2', 'Bob', 22}。
假设我们的查询中没有其他常量。
那么,DOM(Φ) 就是 {'S1', 'Alice', 20, 'S2', 'Bob', 22}。
安全约束的要求:任何安全的查询,其结果元组的每一个分量(值),都必须是 DOM(Φ) 集合中的一员。
将不安全的查询变得安全
现在我们来修正之前的“不安全查询”。我们不能问“谁不是我们的学生”,因为范围太广了。我们必须提供一个有限的候选范围。
假设我们还有一个候选人表 Candidate:
新查询:找出在候选人名单中,但不是我们学校学生的人。
表达式:{ t | Candidate(t) ∧ ¬S(t) }
这个查询为什么是安全的?
DOM(Φ):
公式 Φ 引用了 Candidate 表和 S 表。
DOM(Φ) = { 'S1', 'Alice', 20, 'S2', 'Bob', 22, 'S3', 'Charlie', 21 }。这是一个有限的集合。
查询逻辑:
Candidate(t):这个条件将我们的查询范围 t 限定在了 Candidate 表的两行之内。我们只需要检查 t = ('S1', 'Alice', 20) 和 t = ('S3', 'Charlie', 21) 这两种情况。
¬S(t):对上述限定范围内的 t 进行判断。
当 t = ('S1', 'Alice', 20) 时,S(t) 为真,所以 ¬S(t) 为假。
当 t = ('S3', 'Charlie', 21) 时,S(t) 为假,所以 ¬S(t) 为真。
结果:
只有 t = ('S3', 'Charlie', 21) 满足 Candidate(t) ∧ ¬S(t)。
最终结果是 { ('S3', 'Charlie', 21) }。
这个结果是有限的,并且结果中的所有值 'S3', 'Charlie', 21 都来自于 DOM(Φ)。
总结:通过增加 Candidate(t) 这个条件,我们为查询提供了一个有限的“域”或“范围”,从而确保了查询的安全性。DOM(Φ) 的概念就是这个“安全范围”的数学化表达。