多对多 - 简介¶
我们了解了如何处理数据中的一对多关系。
但是,如何处理多对多关系呢?
让我们来探索一下。🚀
从一对多开始¶
让我们从熟悉且更简单的一对多选项开始。
我们有一个团队表和一个英雄表,对于每个一个团队,我们可以有多个英雄。
由于每个团队可以有多个英雄,我们无法在team表中为所有英雄的ID都放入列中。
但是由于每个英雄只能属于一个团队,所以在英雄表中有一个单一列指向特定团队(指向team表中的特定行)。
team表如下所示
| id | name | 总部 |
|---|---|---|
| 1 | 阻止者 | 锐利之塔 |
| 2 | Z-部队 | 玛格丽特修女酒吧 |
提示
请注意,它不包含任何指向其他表的外部键。
hero表如下所示
| id | name | secret_name | age | team_id |
|---|---|---|---|---|
| 1 | 死侍 | 戴夫·威尔逊 | 空 | 2 |
| 2 | 蜘蛛男孩 | 佩德罗·帕尔克多 | 空 | 1 |
| 3 | 锈人 | 汤米·夏普 | 48 | 1 |
在hero表中,我们有一个team_id列,它指向team表中特定团队的ID。
这就是我们连接每个hero和team的方式
请注意,每个英雄只能有一个连接。但是每个团队可以接收多个连接。特别是,预防者团队有两名英雄。
引入多对多¶
但假设死侍是一个很棒的角色,他们把他招募到新的预防者团队,但他仍然是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 |
信息
此连接表的其他名称是
- 关联表
- 辅助表
- 连接表
- 中间表
- 联结表
- 通过表
- 关系表
- 连接表
我使用“连接表”一词是因为它简短,不与其他已用术语(例如“关系”)冲突,易于记忆其写法等。
连接主键¶
太棒了,我们有一个只有两列的连接表。但是请记住,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和代码来处理它们。🚀