有一个人的表,我想链接到彼此,多对多,链接是双向的

时间:2010-05-21 05:34:12

标签: many-to-many data-modeling

想象一下,你生活在一个非常简单的例子中 - 想象一下你的MySQL数据库里有一张人的表:

create table person (
    person_id int,
    name text
)

select * from person;

+-------------------------------+
|   person_id |            name |
+-------------------------------+
|           1 |           Alice |
|           2 |             Bob |
|           3 |           Carol |
+-------------------------------+

这些人需要协作/一起工作,所以你有一个链接表,将一个人的记录链接到另一个人:

create table person__person (
    person__person_id int,
    person_id int,
    other_person_id int
)

这种设置意味着人们之间的链接是单向的 - 即Alice可以链接到Bob,而Bob没有链接到Alice,更糟糕的是,Alice可以链接到Bob Bob可以链接到Alice同时,在两个单独的链接记录中。由于这些链接代表了工作关系,在现实世界中它们都是双向的相互关系。以下是此设置中的所有内容:

select * from person__person;

+---------------------+-----------+--------------------+
|   person__person_id | person_id |    other_person_id |
+---------------------+-----------+--------------------+
|                   1 |         1 |                  2 |
|                   2 |         2 |                  1 |
|                   3 |         2 |                  2 |
|                   4 |         3 |                  1 |
+---------------------+-----------+--------------------+

例如,上面的person__person_id = 4,当您查看Carol(person_id = 3)个人资料时,您应该看到与Alice的关系(person_id = 1),当您查看Alice的个人资料时,您应该看到与Carol的关系,即使链接是另一种方式。

我意识到我可以做联合和不同的查询以及在UI中将关系呈现为相互关系,但是有更好的方法吗?我有一种感觉, 是一种更好的方式,通过正确设置数据库可以巧妙地消除这个问题,但我看不到它。有人有更好的主意吗?

4 个答案:

答案 0 :(得分:3)

我不确定是否有更好的配置表格的方法。我认为你拥有它们的方式是正确的,并且将是我实现它的方式。

由于您的关系表可以表示单向关系,我建议您将其视为单向关系。换句话说,对于每个关系,我会添加两行。如果Alice与Bob合作,该表应该如下:

select * from person__person;
+---------------------+-----------+--------------------+
|   person__person_id | person_id |    other_person_id |
+---------------------+-----------+--------------------+
|                   1 |         1 |                  2 |
|                   2 |         2 |                  1 |
+---------------------+-----------+--------------------+

原因是因为在很多类似系统的ActiveRecord(Rails)中,多对多表对象不够智能,无法查询person_id和other_person_id。通过保留两行,ActiveRecord之类的对象将正常工作。

然后,您应该在代码级别强制执行数据的完整性。每次在两个用户之间建立关系时,应插入两个记录。当关系被破坏时,应删除两个记录。不应允许用户与自己建立关系。

答案 1 :(得分:2)

没有更好的主意。关系数据库无法强制执行您的要求,因此您必须编写特殊查询来检索数据和触发器来强制执行约束。

为了获得@person的相关人员,我会选择:

SELECT CASE person_id WHEN @person 
           THEN other_person_id 
          ELSE person_id
       END as related_person_id  
FROM person_person 
WHERE (  person_id=@person 
      OR other_person_id=@person)

答案 2 :(得分:2)

我无法使用简单的关系概念。您必须添加“业务”代码才能强制执行您的人与人之间的关系。

  • 一种方法可能是使用插入触发器强制执行第二个关系记录
  • 然后声明其中一个记录“primary”(例如person_id小于另一个_person_id的记录)
  • 然后为您的应用程序(选择,更新,删除)构建视图和粘合代码,以便用这些知识访问数据。

答案 3 :(得分:2)

你会觉得这篇文章很有用:

http://discuss.joelonsoftware.com/default.asp?design.4.361252.31

正如@user发布的那样,你通常最好每个双向关系创建两个记录(在你的例子中,Alice到Bob和Bob到Alice)。它使查询更多 更容易,它准确地反映了人际关系。如果你确实有真正的单向关系,那么这是唯一的飞行方式。