关系模型 (Relational Model) 笔记
1. 基本概念
关系数据库是基于关系模型的,其核心是将数据组织在一系列的二维表中。
- 域 (Domain): 属性的允许值集合,例如
customer_names,account_numbers。每个值都是原子的,即不可再分的 。
- 关系模式 (Relation Schema):
定义了一张表的结构,包括关系名和属性列表。
- 示例:
Customer_schema = (customer_name, customer_street, customer_city)。
- 示例:
- 关系实例 (Relation Instance):
特定时刻表中的数据,是一个元组(行)的集合 。
- 元组 (Tuple): 表中的一行,代表一组相关的数据值
。
- 属性 (Attribute): 表中的一列,代表元组中的一个特定属性 。
重要特性:
- 关系内的元组顺序无关 。
- 属性的顺序也无关紧要,通过属性名来引用 。
2. 键 (Keys)
键用于唯一标识和关联表中的数据。
- 超码 (Superkey):
一个或多个属性的集合,其值可以唯一标识关系中的一个元组
。
- 候选键 (Candidate Key):
最小化的超码,即移去任何一个属性后就不再是超码 。
- 主键 (Primary Key):
从一个或多个候选键中选出的一个,用作元组的主要标识符 。
- 外键 (Foreign Key):
一个关系中的属性(或属性集),其值引用了另一个关系的主键,用于建立表之间的联系
。
- 参照完整性约束 (Referential Integrity):
强制要求外键的值要么必须匹配被引用关系中某个元组的主键值,要么为
NULL。
3. 关系代数 (Relational Algebra)
这是一种过程化查询语言,通过组合一系列运算来构建查询。
3.1 基础运算
- 选择 (Select -
): 选取满足特定条件的元组(行)。 - 语法:
,其中 是选择条件,r是具体的表格
- 示例:
- 选择 instructor表中所有在物理系的教师。
- 语法:
- 投影 (Project -
): 选取特定的属性(列)。 - 语法:
,其中 是属性列表。
- 示例:
- 从 instructor表中选择ID、姓名和薪水这三列。
- 语法:
- 并集 (Union -
): 合并两个关系的元组,并自动去除重复行。 - 语法:
- 语法:
- 差集 (Set Difference -
): 返回存在于第一个关系但不存在于第二个关系中的元组。 - 语法:
- 语法:
- 笛卡尔积 (Cartesian Product -
): 将两个关系的每一行进行组合。 - 语法:
- 语法:
- 重命名 (Rename -
): 改变关系或其属性的名称。 - 语法:
将表达式 E 的结果重命名为 x。
- 语法:
3.2 附加运算 (Additional Operations)
这些运算虽然可以由基础运算组合而成,但因为常用,所以被定义为独立的运算符。
交集 (Set Intersection -
)
- 目的:
找出同时存在于两个关系(表)中的元组(行)。
- 语法:
- 解释: 返回的结果集中包含了所有既属于关系
又属于关系 的元组。
- 约束:
参与运算的两个关系必须是并兼容的(即它们具有相同数量的属性,并且对应属性的域也相同)。
- 示例: 假设有两个课程列表,一个是秋季学期开设的课程
(
FallCourses),另一个是春季学期开设的 (SpringCourses)。要找出两个学期都开设的课程:
Π_course_id(FallCourses) ∩ Π_course_id(SpringCourses)
3.2.1
自然连接 (Natural Join - ):像拉拉链一样合并信息
核心思想: 把两张有共同点的表,像拉链一样合并成一张更详细的表。
生活中的例子:
假设你有两张清单:- 同学名单 (
instructor表)
- 班级信息表 (
department表)
instructor(教师表)
| ID | name | dept_name |
| :— | :— | :— |
| 10101 | Srinivasan | Comp. Sci. |
| 12121 | Wu | Finance |
| 32343 | El Said | History |department(院系表)
| dept_name | building |
| :— | :— |
| Comp. Sci. | Taylor |
| Finance | Painter |这两张表的共同点是
dept_name(院系名称)这一列。- 同学名单 (
运算过程:
执行自然连接instructor ⋈ department时,数据库会:- 找到两个表中同名的列 (
dept_name)。
- 将
instructor表中的每一行,与department表里dept_name值相同的那一行进行“拼接”。
- 拼接后的新表中,
dept_name这一列只保留一个,不会重复出现。
- 找到两个表中同名的列 (
结果 (一张更详细的表):
| ID | name | dept_name | salary | building |
| :— | :— | :— | :— | :— |
| 10101 | Srinivasan| Comp. Sci. | 65000 | Taylor |
| 12121 | Wu | Finance | 90000 | Painter |
注意:
History系的 “El Said” 老师没有出现在结果里,因为department表中没有 “History” 这一行,无法匹配。自然连接只保留能成功匹配的行。
3.2.2 除法 (Division - ÷):查找“全能冠军”
核心思想: 找出那些满足了所有条件的记录。专门用来回答带有“所有”、“每一个”这类词的问题。
生活中的例子:
假设你有一个记录所有学生选课情况的表格,和一个记录了“核心必修课”的清单。1. 学生选课总表 (r)
| StudentID | Course |
| :— | :— |
| 101 | 数学 |
| 101 | 物理 |
| 101 | 英语 |
| 102 | 数学 |
| 102 | 英语 |
| 103 | 物理 |2. 核心必修课清单 (s)
| Course |
| :— |
| 数学 |
| 物理 |问题: 哪些学生选修了所有的核心必修课?
运算:(学生选课总表) ÷ (核心必修课清单)运算过程:
- 系统先看清单
s,要求是必须同时拥有“数学”和“物理”的记录。
- 然后去总表
r里检查每个学生:- 学生101:
选了数学吗?选了。选了物理吗?选了。✅
满足所有条件。
- 学生102:
选了数学吗?选了。选了物理吗?没选。❌
不满足所有条件,被排除。
- 学生103: 选了数学吗?没选。❌ 不满足所有条件,被排除。
- 学生101:
选了数学吗?选了。选了物理吗?选了。✅
满足所有条件。
- 系统先看清单
结果 (全能冠军的名单):
| StudentID |
| :— |
| 101 |最终结果就是学生
101,因为只有他满足了“一个都不能少”的条件。
赋值 (Assignment - )
- 目的:
将一个复杂的查询表达式的结果保存到一个临时的关系变量中,以便在后续的查询中重复使用。这使得复杂查询的步骤更清晰。
- 语法:
temp_relation ← expression
- 示例: 找出所有在 “Physics” 系且薪水超过
的教师姓名。 high_paid_physics_profs ←
result ←
3.3 扩展运算 (Extended Operations)
这些运算提供了更强大的数据处理和计算能力。
广义投影 (Generalized Projection)
- 目的: 允许在投影操作中进行计算或重命名列。
- 语法:
- 解释: 与基本投影不同,这里的
不仅可以是属性名,还可以是涉及属性、常量和算术运算符(+, -, *, /)的表达式。
- 示例:
给所有教师涨薪10%,并显示他们的ID、姓名和新薪水。
外连接 (Outer Join)
- 目的:
在连接操作中保留那些在另一个关系中没有匹配项的元组,用
NULL填充缺失的属性值。
- 左外连接 (Left Outer Join - ⟕):
- 语法:
- 解释: 返回两个关系自然连接的结果,并加上关系
中所有在关系 中找不到匹配的元组(右侧属性填充为 NULL)。
- 示例:
instructor ⟕ teaches会列出所有教师,即使某个教师没有授课记录。对于没有授课的教师,course_id,sec_id等来自teaches表的字段将为NULL。
- 语法:
- 右外连接 (Right Outer Join - ⟖):
- 语法:
- 解释: 与左外连接相反,保留右侧关系
中的所有元组。
- 语法:
- 全外连接 (Full Outer Join - ⟗):
- 语法:
- 解释:
保留两个关系中的所有元组,无论它们是否有匹配。没有匹配的部分用
NULL填充。
- 语法:
4. 数据库修改
- 删除 (Deletion): 使用差集运算
来删除满足条件的元组 。
- 插入 (Insertion): 使用并集运算
来添加元组 。
- 更新 (Update): 通过广义投影实现,可以对属性值进行计算和修改 。
5. NULL 值处理
- 定义:
NULL表示值未知或不存在 。
- 运算: 任何涉及
NULL的算术运算结果仍为NULL。
- 比较:
NULL值的比较结果为 unknown。
- 聚集函数: 通常会忽略
NULL值 。
例题:找出薪水最高的员工姓名
三张表:
employee(ID, person_name, street , city)
works(ID, company_name, salary)
company(company_name,city)
分步实现:
第一步:找出所有低于最高薪水的薪水值集合。
- 为了比较
works表自身,我们创建两个副本并重命名:w1和w2。
- 然后找出所有
w1.salary < w2.salary的情况,并投影出w1.salary。
- 为了比较
第二步:用所有薪水的集合减去“非最高薪水”的集合,得到最高薪水。
- 首先获取所有薪水的集合:
- 然后执行差集运算。
- 此时,
Max_Salary这个临时关系里只包含一个值:最高的薪水。
- 首先获取所有薪水的集合:
第三步:利用最高薪水值,通过自然连接找到对应员工的姓名。
- 首先找到拥有最高薪水的员工的记录(包含ID)。
- 然后与
employee表连接以获取姓名。
- 首先找到拥有最高薪水的员工的记录(包含ID)。
完整的关系代数表达式
如果将以上步骤合并成一个表达式,会是这样:
如果您喜欢我的文章,可以考虑打赏以支持我继续创作.