这是一个多对多的关系,这是一个relator表是必需的。
create table Person (
person_id int not null primary key,
username varchar(100) not null,
... other_cols ...
)
create table Buddy (
person_id1 int not null,
person_id2 int not null,
primary key (person_id1, person_id2),
foreign key (person_id1) reference Person (person_id),
foreign key (person_id2) reference Person (person_id)
)
因此Person表格显然会为每个Person包含1行。它将包含任何关于伙伴的数据,因为这会使其非规范化。相反,好友列表将包含人员之间的关系。
因此,可以说你在Person表是这样的:
person_id username
1 George
2 Henry
3 Jody
4 Cara
亨利和卡拉是哥们,因为是乔治和卡拉这样:
person_id1 person_id2
2 4
1 4
如果你需要把它这样的关系不隐含相互,那么你将需要添加额外的行,使其明确。所以现在可以说,亨利认为卡拉好友和卡拉同样认为亨利的好友,而乔治认为卡拉当哥们,但卡拉不与乔治回报:
person_id1 person_id2
2 4
4 2
1 4
失踪4 1表示卡拉不认为乔治是一个好友。这使得事情变得非常干净并且避免了数据异常。您可以调整关系而不会使用Person数据。您也可以在外键上定义删除级联规则,以便删除Person将自动删除所有关联关系。相反,您可能想要阻止这种情况,而不是在这种情况下,您可以在外键上指定restrict(默认值),以防止删除尚未定义关系的Person。
查询是太容易了:
多少哥们确实卡拉有(让我们假设对于好友列表关系是隐含的):
select count(*) from Person
join Buddy on person_id = person_id1 or person_id = person_id2
where name = 'Cara'
对于其中的关系是不是暗示它可能是更好的情况下改为重命名列如下:
person_id considers_as_buddy_id
2 4
4 2
1 4
4 3
select count(*) from Person P
join Buddy B on P.person_id = B.person_id
where name = 'Cara'
这会返回卡拉认为有多少人是好友。在这种情况下2.虽然乔迪不认为卡拉是一个好友 - 所以要找出相互的关系,你会这样做:
select count(*) from Person P
join Buddy B on P.person_id = B.person_id and
B.considers_as_buddy_id = P.person_id
where name = 'Cara'
谢谢你的详细答案。两者都非常有帮助。 – huntaub 2010-06-21 18:00:17
在一个普通的MySql盒子上,如果有人拥有20,000个好友,并且想在<1秒内将所有列表拉出来,那么这是一个可用的设计吗? – 2011-11-29 15:45:49