2.2.1 关系的三类完整约束
1.实体完整性:
主键中任一个都不能为空
2.参照完整性:
F:外键,必须和 S 的主键 K_S 类型、含义一致
那么 R 中每个元组在 F 上的取值只能是以下两种情况之一:
- 取空值:
F的每个属性值都为空(NULL),表示暂时没有引用关系 - 取有效值:等于
S中某个元组的主码值,即必须引用一个真实存在的主键
例:(1)两个:学生(学号,姓名,出生年月,籍贯,专业号) 专业(专业号,专业名)
(2)两个以上关系间的属性引用例设学生实体型、课程实体型及它们之间联系选修可以用如下三个关系模式表示:
学生(学号,姓名,年龄,籍贯,专业号)课程(课程号,课程名)选修(学号,课程号,成绩)
(3)同一关系内部属性间的引用例设课程之间有先修、后修联系,用关系模式可表示为:课程(课程号,课程名,先修课程号)。
3.自定义完整性
用户自定义完整性是用户根据具体业务需求,为数据库数据设定的特殊约束规则(比如年龄在 0-150 之间、成绩在 0-100 之间)。
2.3 关系操作
类型
关系查询
-
关系内查询:只在一张表里查数据(比如只查 “学生” 表,找所有年龄大于 18 的学生)
-
多关系间查询:要跨多张表联合查询(比如要查 “学生选了哪些课”,就需要关联学生表、课程表和选修表)
关系更新
插入 删除 修改
2.3.2 关系运算
关系操作本质是对“表”的运算,分为关系代数(过程式,讲“怎么查”)和关系演算(描述式,讲“要什么”);关系代数、元组演算、域演算三者表达能力等价。
运算符
关系代数有5种基本运算:并、差、笛卡尔积、选择、投影; 交、连接、除等是组合运算,可由基本运算推导,不增加表达能力,仅简化写法。
例:所有职工=已退休 交 未退休
选择
投影
投影运算就是从表里 “选列”,只保留你需要的属性,生成一张新表(垂直方向的子集),并且会自动去掉重复行。
例子:对学生表 学生(学号,姓名,年龄,籍贯) 做投影 姓名籍贯学生,就会得到只包含 “姓名 + 籍贯” 两列的新表,且重复的行被合并。 核心:垂直裁剪 + 去重。
连接(Join)
连接是把两个表按条件拼起来的运算,本质是对笛卡尔积做筛选+投影,最常用的是等值连接(按属性值相等来连)。
- 比如:把「学生表」和「选修表」按「学号相等」连接,就能得到每个学生的选课信息。
等值连接
自然连接
除(Division)
除运算用来表达“全部都满足”的查询,比如“选了所有课程的学生”。
- 它的结果是:在表R中,找到那些与表S的每一个元组都能匹配的元组所对应的属性值。
- 比如:学生表R(学号,课程号) ÷ 课程表S(课程号),结果就是选了所有课的学生学号。
一句话总结:
- 连接:按条件把两张表横向拼接。
- 除:找“包含另一张表全部内容”的那些记录。
用例
不是必须:如果
选课 表本身就只包含 学号 和 课程号 两列,那么直接写 选课 ÷ Π_课程号(课程) 即可。
2.4.1 关系代数概述
改名
广义投影
算术函数对投影扩展
赋值
外连接
🌰 外连接例子(学生-选课场景)
假设我们有两张表:
-
学生表 Student:
Sno(学号), Sname(姓名)Sno Sname 001 张三 002 李四 003 王五 -
选课表 SC:
Sno(学号), Cno(课程号)Sno Cno 001 C01 001 C02 002 C01
1️⃣ 自然连接(只保留匹配的记录)
SELECT * FROM Student NATURAL JOIN SC;
结果:
| Sno | Sname | Cno |
|---|---|---|
| 001 | 张三 | C01 |
| 001 | 张三 | C02 |
| 002 | 李四 | C01 |
❌ 问题:王五(003)没有选课,在结果中被丢弃了。
2️⃣ 左外连接(保留左表所有记录,匹配不到填 NULL)
SELECT * FROM Student LEFT OUTER JOIN SC ON Student.Sno = SC.Sno;
结果:
| Sno | Sname | Cno |
|---|---|---|
| 001 | 张三 | C01 |
| 001 | 张三 | C02 |
| 002 | 李四 | C01 |
| 003 | 王五 | NULL |
✅ 符合外连接定义:把自然连接时舍弃的“王五”也保留下来,未匹配的课程号填 NULL。
3️⃣ 右外连接(保留右表所有记录,匹配不到填 NULL)
如果我们反过来,用右外连接:
SELECT * FROM Student RIGHT OUTER JOIN SC ON Student.Sno = SC.Sno;
结果和自然连接一样,因为右表 SC 里的记录都能在 Student 里找到匹配。
4️⃣ 全外连接(保留两边所有记录,匹配不到填 NULL)
SELECT * FROM Student FULL OUTER JOIN SC ON Student.Sno = SC.Sno;
结果和左外连接一样,因为右表无额外记录。
💡 一句话总结
外连接就是:在自然连接的基础上,把“没匹配上的行”也留下来,缺失的属性用 NULL 填充,避免数据丢失。
要不要我帮你把这个例子写成关系代数表达式,和 SQL 做对照,方便你写博客?### 🌰 外连接例子(学生-选课场景) 假设我们有两张表:
-
学生表 Student:
Sno(学号), Sname(姓名)Sno Sname 001 张三 002 李四 003 王五 -
选课表 SC:
Sno(学号), Cno(课程号)Sno Cno 001 C01 001 C02 002 C01
1️⃣ 自然连接(只保留匹配的记录)
SELECT * FROM Student NATURAL JOIN SC;
结果:
| Sno | Sname | Cno |
|---|---|---|
| 001 | 张三 | C01 |
| 001 | 张三 | C02 |
| 002 | 李四 | C01 |
❌ 问题:王五(003)没有选课,在结果中被丢弃了。
2️⃣ 左外连接(保留左表所有记录,匹配不到填 NULL)
SELECT * FROM Student LEFT OUTER JOIN SC ON Student.Sno = SC.Sno;
结果:
| Sno | Sname | Cno |
|---|---|---|
| 001 | 张三 | C01 |
| 001 | 张三 | C02 |
| 002 | 李四 | C01 |
| 003 | 王五 | NULL |
✅ 符合外连接定义:把自然连接时舍弃的“王五”也保留下来,未匹配的课程号填 NULL。
3️⃣ 右外连接(保留右表所有记录,匹配不到填 NULL)
如果我们反过来,用右外连接:
SELECT * FROM Student RIGHT OUTER JOIN SC ON Student.Sno = SC.Sno;
结果和自然连接一样,因为右表 SC 里的记录都能在 Student 里找到匹配。
4️⃣ 全外连接(保留两边所有记录,匹配不到填 NULL)
SELECT * FROM Student FULL OUTER JOIN SC ON Student.Sno = SC.Sno;
结果和左外连接一样,因为右表无额外记录。
外部并
把两个结构不一样的表 “强行合并”,保留所有行和列,没数据的地方用 NULL 补上。