表示数据库表中人员之间关系的适当方法是什么?

时间:2010-05-01 18:47:04

标签: database database-design many-to-many self-join

我有一张人的表 - 一个ID主键和一个名字。在我的应用程序中,人们可以与其他人建立0个或更多真实世界的关系,因此杰克可能“为......工作”而汤姆可能会“替换”托尼和鲍勃可能“成为”Rob的员工,Bob也可能“结婚” “玛丽。

在数据库中表示这一点的最佳方法是什么?一个多对多的交叉表?一系列自我加入?一个关系表,每个关系对和类型有一行,我在这两个方向上插入关系的记录?

6 个答案:

答案 0 :(得分: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)  
  

简(孩子)
  马特(孩子)

答案 1 :(得分:2)

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

如果您尝试在单个多对多表中表示多种类型的关系,则违反了Fourth Normal Form


评论:

实际上违反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

这最适用于具有可变数量成员的关系,并且是互惠关系。体育团队的成员是另一个例子。它本质上是群体和人民之间的多对多表格。

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

答案 2 :(得分: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

答案 3 :(得分:0)

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

person1, relation, person2

现在当插入值时,例如,如果约翰是凯利的丈夫,那么

john, is husband of, kelly

并将其应用于凯莉

kelly, is wife of, john

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

答案 4 :(得分:0)

我最近遇到了这种情况,在尝试了几个不同的选项之后最终得到了类似的东西(原谅伪代码模型):

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

class RelationshipMember {
    int Id;
    Person RelatedPerson;
}

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

您可以在关系上放置属性,以便在RelationshipMember上对其类型和属性进行建模,以便在关系中为角色建模(如果需要)。

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

在这个特定的项目中,我使用的是ORM工具(nHibernateFluent 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
)

答案 5 :(得分:0)

@bill K:

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

您最初建议的解决方案(每种关系类型一个表)是否没有遭遇同样的问题?

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

三栏选项就是在我30年前的第一个项目中完成的,我相信它仍然是最好的方法。特别是因为“可能的/相关的人际关系类型集合”是欧姆,在我能想象的任何业务中都是一种相当不稳定的东西。