多对多 - 简介¶
我们已经看到了如何在数据中使用一对多关系。
但是如何处理多对多关系呢?
让我们来探索一下。🚀
从一对多开始¶
让我们从熟悉且更简单的一对多选项开始。
我们有一个包含团队的表和一个包含英雄的表,对于每个一个团队,我们可以拥有多个英雄。
由于每个团队可能有多个英雄,我们将无法在 team
表中为所有英雄的 ID 设置列。
但是由于每个英雄只能属于一个团队,因此我们在英雄表中有一个单列指向特定的团队(指向 team
表中的特定行)。
team
表如下所示
id | name | headquarters |
---|---|---|
1 | Preventers | Sharp Tower |
2 | Z-Force | Sister Margaret's Bar |
提示
请注意,它没有任何指向其他表的外键。
hero
表如下所示
id | name | secret_name | age | team_id |
---|---|---|---|---|
1 | Deadpond | Dive Wilson | null | 2 |
2 | Spider-Boy | Pedro Parqueador | null | 1 |
3 | Rusty-Man | Tommy Sharp | 48 | 1 |
我们在 hero
表中有一列 team_id
,它指向 team
表中特定团队的 ID。
这就是我们将每个 hero
与 team
连接的方式
请注意,每个英雄只能有一个一个连接。 但是每个团队可以接收多个连接。 特别是,Preventers 团队有两个英雄。
介绍多对多¶
但是假设由于 Deadpond 是一个很棒的角色,他们将他招募到新的 Preventers 团队,但他仍然是 Z-Force 团队的一员。
因此,现在,我们需要能够让一个英雄与多个团队连接。 然后,每个团队仍然应该能够接收多个英雄。 因此,我们需要一个多对多关系。
一种效果不佳的简单方法是在 hero
表中添加更多列。 假设我们添加两个额外的列。 现在我们可以将单个 hero
总共连接到 3 个团队,但不能更多。 因此,我们并没有真正解决支持多个团队的问题,只是支持了非常有限的固定数量的团队。
我们可以做得更好!🤓
链接表¶
我们可以创建另一个表,该表表示 hero
和 team
表之间的链接。
此表包含的全部内容是两列,hero_id
和 team_id
。
这两列都是外键,指向 hero
和 team
表中特定行的 ID。
由于这将表示英雄-团队-链接,因此我们称该表为 heroteamlink
。
它看起来像这样
请注意,现在表 hero
不再有 team_id
列,它被此链接表替换。
并且 team
表,就像以前一样,也没有任何外键。
具体来说,新的链接表 heroteamlink
将是
hero_id | team_id |
---|---|
1 | 1 |
1 | 2 |
2 | 1 |
3 | 1 |
Info
此链接表的其他名称包括
- 关联表
- 辅助表
- 连接表
- 中间表
- 连接表
- 通过表
- 关系表
- 连接表
我使用术语“链接表”是因为它很短,不与其他已使用的术语(例如“关系”)冲突,并且很容易记住如何编写它等等。
链接主键¶
太棒了,我们有一个只有两列的链接表。但是请记住,SQL 数据库要求每行都有一个主键,该主键唯一标识该表中的行?
现在,此表中的主键是什么?
我们如何识别每个唯一的行?
我们是否应该添加另一列,使其成为此链接表的主键?不用!我们不必这样做。👌
这两列都是此表中每一行的主键(并且每行只有这两列)。✨
主键是一种在单个表中唯一标识特定行的方法。但是它不必是单个列。
主键可以是表中的一组列,这些列在该表中组合起来是唯一的。
再次检查上面的表,看到每行的 hero_id
和 team_id
的组合都是唯一的吗?
我们不能有重复的主键,这意味着我们不能在 hero
和 team
之间有重复的链接,这正是我们想要的!
例如,数据库现在将阻止类似这样的错误,其中包含重复的行
hero_id | team_id |
---|---|
1 | 1 |
1 | 2 |
2 | 1 |
3 | 1 |
3 🚨 | 1 🚨 |
让一个英雄两次成为同一个团队的成员是没有意义的,对吧?
现在,仅通过使用这两列作为此表的主键,SQL 将负责防止我们重复 hero
和 team
之间的链接。✅
回顾¶
带有回顾的简介! 这很奇怪……但无论如何。🤷
现在您了解了关于多对多关系的理论,以及如何在 SQL 中使用表来解决它们。🤓
现在让我们检查一下如何编写 SQL 和代码来使用它们。🚀