什么是数据建模中的一对一关系?如何在数据库中实现这种关系?本文中的示例将回答这些问题。
数据建模中的实体(表)之间有三种类型的关系:
- 一对多关系(也表示为 1:M)。
- 多对多关系 (M:N)。
- 一对一关系(1:1)。
最常见的关系类型是一对多关系,其中一个实体中的记录可以由另一个实体中的多个记录引用。另一种常见类型是多对多关系。这种类型的关系仅用于逻辑数据模型。在物理数据库中,它必须通过使用一对多关系和联结表来实现。
在本文中,我们将讨论第三种类型的关系:一对一关系。这是数据模型中最不常见的关系类型。我们将提供一对一关系的示例,在 ER 图中显示一对一关系的表示法,并在实践中讨论一对一关系。
一对一关系示例
首先,什么是一对一关系?这是一种关系,其中一个实体(表)中的记录与另一个实体(表)中的一条记录完全相关联。
让我们看看一些现实生活中的一对一关系的例子:
- 国家 - 首都:每个国家都有一个首都。每个首都都是一个国家的首都。
- 人 - 他们的指纹。每个人都有一组独特的指纹。每组指纹只能识别一个人。
- 电子邮件 - 用户帐户。对于许多网站,一个电子邮件地址仅与一个用户帐户相关联,每个用户帐户由其电子邮件地址标识。
- 配偶 - 配偶:在一夫一妻制婚姻中,每个人都只有一个配偶。
- 用户配置文件 - 用户设置。一个用户有一组用户设置。一组用户设置仅与一个用户相关联。
为了清楚起见,让我们将这些示例与不是一对一的关系进行对比:
- 国家 - 城市:每个城市正好位于一个国家/地区,但大多数国家/地区都有许多城市。
- 父/母 - 子/女:每个子/女有两个父/母,但每个父/母可以有多个子/女。
- 员工 - 经理:每个员工只有一个直属主管或经理,但每个经理通常监督许多员工。
在 ER 图中表示一对一关系
与所有关系一样,ER 图中的一对一关系表示为连接两个实体的线。“一”基数用一条直线表示。(“许多”基数用鱼尾纹符号表示。
国家和资本之间的一对一关系可以这样表示:
垂直直线表示“强制性”。此图显示,首都必须有一个国家,一个国家必须有一个首都。
另一种可能性是关系的一方或双方是可选的。可选侧用开口圆表示。这张图说,一个人和他们的指纹之间存在一对一的关系。一个人是强制性的(指纹必须分配给一个人),但指纹是可选的(一个人可能没有在数据库中分配指纹)。
物理数据库中的一对一关系
有几种方法可以在物理数据库中实现一对一关系。
主键作为外键
在数据库中实现一对一关系的一种方法是在两个表中使用相同的主键。主键中具有相同值的行是相关的。在此示例中,法国在表country中
id
为1 ,其首都巴黎在表capital
中的id也为 1 。
country
id | name |
---|---|
1 | France |
2 | Germany |
3 | Spain |
capital
id | name |
---|---|
1 | Paris |
2 | Berlin |
3 | Madrid |
从技术上讲,必须将其中一个主键标记为外键,如以下数据模型所示:
表capital
中的主键也是引用表country
中 id 列的外键。由于capital.id
是主键,因此列中的每个值都是唯一的,因此首都最多可以引用一个国家/地区。它还必须引用一个国家/地区 - 它是一个主键,因此不能留空。
具有唯一约束的附加外键
在数据库中实现一对一关系的另一种方法是添加新列并使其成为外键。
在此示例中,我们在表capital
中添加列country_id
。首都中id为
1,马德里,与国家3,西班牙有关。
country
id | name |
---|---|
1 | France |
2 | Germany |
3 | Spain |
capital
id | name | country_id |
---|---|---|
1 | Madrid | 3 |
2 | Berlin | 2 |
3 | Paris | 1 |
从技术上讲,列country_id
应该是引用表country
中的列id
的外键。由于您希望每个资本只与一个国家/地区相关联,因此应使外键列country_id
唯一。
实践中的一对一关系
很少有一对一的关系持续
一对一关系是最不常见的关系类型。其中一个原因是现实生活中很少有一对一的关系。此外,大多数一对一关系仅在一段时间内是一对一的。如果您的模型包含时间分量并捕获更改历史记录(通常情况下),则只有很少的一对一关系。
一夫一妻制的关系可能会破裂,或者其中一个伴侣可能会死亡。如果您模拟一夫一妻制关系(例如婚姻或民事结合)随时间推移的现实,则可能需要模拟它们仅持续一段时间的事实。
你会认为一个人和他们的指纹永远不会改变。但是,如果这个人失去了一根手指或手指严重烧伤怎么办?他们的指纹可能会改变。这不是一个非常常见的情况;不过,在某些模型中,您可能需要考虑这一点。
即使是像国家及其首都这样看似稳定的东西也会随着时间的推移而变化。例如,波恩在第二次世界大战后曾经是西德的首都,当时柏林是东德的一部分。这在德国统一后发生了变化。德国的首都(德国联邦共和国)现在是柏林。是否应该考虑这一点取决于您的业务现实和您正在处理的应用程序。
可行的1:1方案:表的可选部分
对于真正的一对一关系,我可以想到一个可行的方案:表的可选部分。假设您有一个包含用户数据的表用户。该表包含常规用户信息,例如用户名、电子邮件地址和注册日期。它还包含用户设置,例如该应用的颜色主题或自动登录。但是,大多数用户没有任何用户设置。他们使用默认设置。
user
id | name | signup_ date | theme | autologin | |
---|---|---|---|---|---|
1 | Nathanael Talbot | nat@example.com | 2020-12-12 | dark | true |
2 | Talitha Yates | yates@example.com | 2020-12-14 | ||
3 | Markus Weir | weir@example.com | 2020-12-15 | light | false |
4 | Nathalie Hays | hays@example.com | 2020-12-18 | ||
5 | Maurice Church | mch@example.com | 2020-12-20 | ||
6 | Arwa Valdez | arval@example.com | 2020-12-21 |
此表中有很多空字段。您可以将表user
拆分为两个表:user
和user_settings
,其中包含有关选择用户的用户设置的信息。
user
id | name | signup_ date | |
---|---|---|---|
1 | Nathanael Talbot | nat@example.com | 2020-12-12 |
2 | Talitha Yates | yates@example.com | 2020-12-14 |
3 | Markus Weir | weir@example.com | 2020-12-15 |
4 | Nathalie Hays | hays@example.com | 2020-12-18 |
5 | Maurice Church | mch@example.com | 2020-12-20 |
6 | Arwa Valdez | arval@example.com | 2020-12-21 |
user_settings
user_id | theme | autologin |
---|---|---|
1 | dark | true |
3 | light | false |
将数据拆分为两个表会使表查询更加复杂:您必须联接两个表中的数据。另一方面,主用户表更易于管理。
了解有关数据库关系的详细信息
一对一关系是指一个表中的记录与另一个表中的一条记录完全关联的关系。这种类型的关系在现实生活中很少见。如果在数据模型中包括时间,则许多一对一关系将变为一对多或多对多关系。在数据库中使用一对一关系的最常见方案是将一个表拆分为两个表:一个表包含必需列,另一个表包含可选列。