在关系数据库中对相同实体之间的多个多对多关系进行建模
Posted
技术标签:
【中文标题】在关系数据库中对相同实体之间的多个多对多关系进行建模【英文标题】:Modeling multiple many to many relationships between the same entities in a relational database 【发布时间】:2017-04-26 01:30:05 【问题描述】:当两个表具有多对多关系或当一个表与其自身具有多对多关系时,我们可以使用联结表对其进行建模。
但是关系的类型可以超出原始类型,例如:
要求:我们有用户。每个用户可以有 0 个或多个其他用户作为朋友
解决方案:一个用户表和一个名为“user_user”的联结表。
然后我们发现了一个新要求:一些友谊是浪漫的,或者换句话说,两个用户可以以不同于友谊的方式联系。
解决方案 a:在联结表中添加一列,其中包含友谊类型(朋友 | 合作伙伴 | 前朋友)等。
解决方案 b:将 'user_user' 表重命名为 'friendships'(用这种方法开头会是一个更好的名称)并创建一个名为romass 的新表,同时将用户连接到用户。
然后我们发现另一个新要求:用户可以欠其他用户的钱。同样,我们可以搭载同一个连接表或创建一个名为“债务”的新连接表。这次我的直觉是 100% 有一个单独的表。
每次我们发现一种新的关系类型或已知关系的子类型时,我们都可以向一个联结表添加一列或创建一个新的联结表。
我的问题是,决定何时必须创建新表的好规则是什么?
是不是每个有序对必须有不止一行?例如,如果过去的关系从未被删除,那么如果两个用户在过去两年中成为朋友,失去联系,然后重新成为朋友,我们希望旧行也有开始和结束日期,但有两行使其他列信息重复(旧行显示用户欠钱,新行没有)。
是不是当额外的列在逻辑上不是单一类型关系的定义时?
OK:友谊的开始日期与友谊1对1直接相关
不好:一个用户拥有另一个用户多少钱的列可以是一对一的关系,但逻辑上不是对友谊的描述。
如果我们提前知道两张表会有很多多对多的关系,是不是要计划很多联结表,还是制作一个更灵活的联结表(即使类型连接不是任意的)?
【问题讨论】:
【参考方案1】:这取决于你。您可以将“友谊”定义为与“浪漫相关”不同,因此需要两个联结表。或者您可以将“浪漫参与”定义为“友谊”的特殊情况,因此需要一张桌子。我倾向于后者,因为它更简单,更容易混淆。 (如果同样的两个人既被列为朋友又被列为恋人呢?)
但是,“欠钱”是不同的。如果 A 和 B 是朋友,那么 B 和 A 是朋友。但是如果 A 欠 B 钱,说 B 欠 A 钱是错误的。所以你不仅定义了一种不同的关系,而且定义了一种不同的关系。哪个字段包含对 A 的引用以及哪个字段包含对 B 的引用变得重要。为此,最好有一个单独的连接表。
【讨论】:
【参考方案2】:TL;DR表格代表应用程序/业务关系/关联。与实体-关系模型一样。即关系。就像在关系模型中一样。每次我们对不同的关系感兴趣时,我们都会考虑一个新的(“联结”/“关联”)表。 规范化告诉我们何时以及如何将关系/表分解为其他关系/表或将一些组合为一个。
我们通过一些谓词(即语句模板)来识别关系,一行构成一个命题,即语句,说明我们对应用程序感兴趣的内容.从表的谓词中做出正确陈述的行进入表中。
Employee(e, n, ...) -- employee identified by E is named N and ...
Manages(e, m) -- employee M manages employee E
如果不知道表的谓词,您就无法知道表对应用程序的描述或根据应用程序设置它!当您陈述“关系”的“基数”时,您必须首先确定您正在谈论的关系/关联/谓词。
(不幸的是,许多所谓的 ER 方法和产品都使用“关系”来表示表的外键。)
当我们可以从新表中重建原始表时,我们可以将多个表合并为一个表或用其他表替换一个表。在这里我们可以将上面的表格组合成
-- employee identified by E is named N and ... AND employee M manages employee E
EmployeeM(e, n, ..., m)
这恰好总是 Employee & Manages 的 JOIN,因为 JOIN 的谓词是其参数的谓词的 AND。但是因为 E 是一组公共列并且它在其中一个列中是唯一的,所以我们可以通过新的投影来重建原始列。
当员工只能拥有一个经理时,这将是一个合理的设计。但是,如果员工可以有一个或多个经理,那么该表虽然仍将包含满足该谓词并允许重建原始数据的行,但会出现更新异常,因此我们更喜欢原始数据。如果员工可以有零个或一个或零个或多个经理,那么我们仍然可以使用该表,但不仅该表,因为它无法告诉我们没有经理的员工。 (最初的设计是这样的。)我们还需要一个 like Employee 表,但具有 不同的谓词 employee identified by E is named N and ... AND E has no manager.
或者我们可以只使用一个表 like EmployeeM 但允许 nulls 通过 不同的谓词 employee identified by E is named N and ... AND ( employee M manages employee E OR M IS NULL AND E has no manager )
。
阅读原始 Chen ER 模型/方法,其中有实体类型、图标和表格以及关系类型、图标和表格。每种关系类型都清楚地描绘为菱形。每一行都清楚地表示实体类型(可能是关联实体类型)在关系类型中的参与,即清楚地表示表之间的 FK。而许多所谓的 ER 方法甚至不区分实体和关系。 (这不需要是好是坏,但他们的演示文稿往往不会解释如何正确建模。)
关系模型本身并不关心实体和关系。它的表只是值上的关系。 ER 和所谓的 ER 方法在实体和关系之间进行了不必要的和限制性的任意区分。自然,表仍然可以像在 ER 模型中一样说明它对应用程序的作用,因为值的子行可以识别实体。见this answer。
规范化 告诉您何时以及如何将关系的谓词/表分解为更小的关系(即它的投影,即 AND/JOIN 回到它),并告诉您何时以及如何将多个关系的谓词/表合并为一个(通过 AND/JOIN,使用投影重构)。
PS 重复值本身并没有错。可能会出现的问题是,根据您选择的谓词,多行通过在表中或不在表中来暗示应用程序的相同内容。并非所有这些冗余都是错误的。只是不受控制的冗余是错误的。一般来说,我们希望设计尽可能多地采用 5NF。 (即减少更新异常、谓词复杂性和约束。)
【讨论】:
以上是关于在关系数据库中对相同实体之间的多个多对多关系进行建模的主要内容,如果未能解决你的问题,请参考以下文章