2010-05-21 33 views
6

想象一下,你生活在非常简单的例子土地 - 和想象你已经有了一个人在一个表你的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 
) 

这样的设置意味着之间的联系人们是单向的 - 即爱丽丝可以链接到鲍勃,而鲍勃连接到爱丽丝,甚至w ORSE,爱丽丝可以链接到鲍勃 Bob可以同时链接到爱丽丝,在两个单独的链接记录。由于这些链接代表了工作关系,在现实世界中,它们都是双向的相互关系。在这个设置中,以下是所有可能的:

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的关系。

我知道我可以做工会和不同的查询和诸如此类的东西呈现在用户界面相互之间的关系,但有没有更好的办法?我有一种感觉,有一个更好的办法,一个地方这个问题会整齐地融化掉通过适当设置数据库,但我不能看到它。任何人有更好的主意?

+3

这是我从<50代表用户见过的格式最好的问题!干杯! – 2010-05-21 05:46:32

+1

我将标记从'mysql many-to-many'更改为'data-modeling many-to-many'(+1 nice question!) – lexu 2010-05-21 06:07:49

+1

+1陈述得很好的问题。 nit-pick:person__person是一个可怕的表名;只是声称它是用于照明目的;) – msw 2010-05-21 06:25:59

回答

3

我不知道如果有配置表一个更好的办法。我认为你拥有它们的方式是正确的,并且将是我实施它的方式。

由于您的关系表可以表示单向关系,所以我会建议对待它们。换句话说,对于每一个关系,我都会添加两行。如果爱丽丝与鲍勃合作,表应该是如下:

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

的原因是因为在很多的ActiveRecord(滑轨)的类似系统,许多一对多表对象是不够聪明查询person_id和other_person_id。通过保持两行,ActiveRecord类似的对象将正常工作。

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

+1

这也具有业务逻辑的优点,即决定不是所有的关联都是双向的,而且架构不需要改变。 – msw 2010-05-21 06:18:05

+0

完成并完成!非常感谢 - 我将采用这种方法,因为user239098和msw都声明了所有原因。 – 2010-05-21 07:54:05

2

有没有更好的主意。关系数据库不能执行你所要求的,所以你必须编写一个特殊的查询来检索数据和一个触发器来执行约束。

要得到相关人士的@person我会去:

SELECT CASE person_id WHEN @person 
      THEN other_person_id 
      ELSE person_id 
     END as related_person_id 
FROM person_person 
WHERE ( [email protected] 
     OR [email protected]) 
+0

始终在where子句中放置()或'或'。如果在添加更多限制之前忘记了,就会发生不好的事情! (答案为+1) – lexu 2010-05-21 06:11:33

2

我无法看到使用简单的关系概念。你将不得不添加“商业”代码来执行你的人际关系。

  • 一种方式是使用插入触发
  • 执行的第二关系记录则声明的记录中的一个“主”(例如,一个,其中为person_id比其它_person_id小)
  • 然后根据这些知识为您的应用程序构建视图并粘贴代码(选择,更新,删除)。
2

你会发现这篇文章有用:

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

由于@user贴出你一般都是最好创建两个记录每双向关系(爱丽丝和鲍勃鲍勃爱丽丝在你的例子)。它使得查询更容易,并且准确地反映了这些关系。如果你确实有真正的单向关系,那么这是唯一的飞行方式。

+0

谢谢,我读了这个帖子;它基本上证实了'只存两次'的解决方案,接着是一大堆呐喊。我很高兴stackoverflow是不是这样:) – 2010-05-21 07:47:00