4

我有一张人员表——一个 ID 主键和一个名字。在我的应用程序中,人们可以与其他人有 0 个或多个现实世界的关系,因此杰克可能“为”简“工作”,汤姆可能“取代”托尼和鲍勃,可能“成为”罗伯的雇员,鲍勃也可能“结婚”到”玛丽。

在数据库中表示它的最佳方式是什么?多对多相交表?一系列自加入?一个关系表,每个关系对和类型都有一行,我在其中插入两个方向的关系记录?

4

6 回答 6

4

为每种类型的关系创建一个单独的多对多表。

如果您尝试在单个多对多表中表示多种类型的关系,则违反了第四范式


重新评论:

实际上违反 4NF 是这样的:

Person1 Person2 Is_Employer Is_Teacher Is_Father
Tom     John     No          No         Yes

如果你有一个列出两个人和一种关系类型的三列表,那就更好了,但你仍然有互惠关系的问题。

Person1 Person2  Rel_type
John     Ann     married

有些人对是否存储两行感到困惑,或者以某种一致的顺序存储两个人(例如,较低的 ID 值优先)。但是还有一些关系是直接的,比如“雇主”,其中命令意味着什么。并且有多个人的关系,比如“兄弟姐妹”。

因此,组织这些关系的另一种方法是创建一个列出组的表,每行一个组,然后另一个表列出该组中的人员。

Group Rel_type    Group Person
123   siblings    123   Bobby
                  123   Peter
                  123   Greg
                  123   Cindy
                  123   Jan
                  123   Marsha

这对于具有可变数量的成员并且是互惠关系的关系最有效。运动队的成员是另一个例子。它本质上是组和人之间的多对多表。

您可能需要多种方式来存储关系,以考虑所有不同的类型。

于 2010-05-01T18:52:27.673 回答
3

我知道这是一个旧线程,但仍然相关。

假设玛丽和约翰结婚并有两个孩子,简和马特......

这个表结构怎么样:

side1    | side1type    | side2type    | side2
----------------------------------------------------
Mary     | wife         | husband      | John
Jane     | child        | mother       | Mary
Jane     | child        | father       | John
Matt     | child        | mother       | Mary
Matt     | child        | father       | John 
Jane     | sister       | brother      | Matt

当我们有兴趣找到一个人的亲戚时,我们可以运行 2 个查询,在 side1 列中查找该人,然后在 side2 列中查找该人......

或者也许一个查询在一列或另一列中寻找那个人,而不是我们在我们的应用程序中使用逻辑并且:

If that person has been found in side1 column 
   we print side1, side1type, "of ", side2  

玛丽是约翰的妻子

If that person has been found in side2 column 
   we print side2, side2type, "of ", side1  

玛丽是简
的母亲 玛丽是马特的母亲

或者更优雅……

If that person has been found in side1 column 
   we print side2 (side2type)  

约翰(丈夫)

If that person has been found in side2 column 
   we print side1 (side1type)  

简(孩子)
马特(孩子)

于 2016-06-10T07:07:20.747 回答
1

确保在链接表中包含日期。因为一段感情不会长久……

**person**
person_id
name

**person_person**
person_id_1
person_id_2
relationship_type_id
begin_date
end_date

**relationship_type**
relationship_type_id
name
于 2010-05-02T14:03:27.633 回答
0

我最近遇到了这种情况,在尝试了几个不同的选项后,结果是这样的(请原谅伪代码模型):

class Person {
    int Id;
    List<RelationshipMember> Relationships;
}

class RelationshipMember {
    int Id;
    Person RelatedPerson;
}

class Relationship {
    int Id;
    List<RelationShipMember> RelationshipMembers;
}

如果需要,您可以将属性放在关系上以对其类型进行建模,并将属性放在关系成员上以对关系中的角色进行建模。

当然,这也允许三人一组。:)

在这个特定的项目中,我使用了一个 ORM 工具(nHibernate with Fluent Automapping),这是数据库表的表达方式:

TABLE Person (
   Id int NOT NULL
)

TABLE Relationship (
   Id int NOT NULL
)

TABLE RelationshipMember(
Id int NOT NULL,
Relationship_id int NOT NULL,
    Person_id int NOT NULL
)
于 2010-05-01T19:10:14.457 回答
0

您可以设计具有以下结构的表,

person1, relation, person2

现在,当向其中插入值时,例如,如果 john 是 kelly 的丈夫,那么

john, is husband of, kelly

并适用于凯利

kelly, is wife of, john

您将需要为两个人定义关系,但它会在获取时产生良好的结果。

于 2010-05-01T18:55:02.410 回答
0

@比尔K:

“如果你有一个列出两个人和一个关系类型的三列表,那就更好了,但你仍然有互惠关系的问题。”

您首先建议的解决方案(每种关系类型一个表)不会遇到同样的问题吗?

顺便说一句,imo,您的术语(“互惠”)不正确。您正在谈论具有对称性的关系(数学意义) 。据我所知,理论留下的一个领域的回答非常不令人满意。

三栏选项是我在大约 30 年前的第一个项目中的做法,我相信它仍然是最好的方法。特别是因为“可能/相关的人际关系类型”在我能想象的任何业务中都是一种相当不稳定的事情。

于 2010-05-03T20:26:25.143 回答