2012-05-17 50 views
6

我在我的数据库中的两个表一个是保持用户信息(users_table) ,另一种跟踪的朋友改善好友列表查询:数着共同的朋友

users_table:

id username  avatar 
1   max  max.jpg 
2   jack  jack.jpg 

friends_table:

id u1_id  u2_id 
1   1   2 
2   1   3 

在每个用户的个人资料我展示他/她的朋友列表

这里是我的查询

select u.id, 
    u.username, 
    u.avatar 
from friends_table f 
join users_table u on f.u1_id = u.id || f.u2_id = u.id 
where u.id <> $profile_id 
    and (f.u1_id = $profile_id || f.u2_id = $profile_id) 

此查询选择配置文件所有者的朋友($ PROFILE_ID)

,并与用户表让每个朋友的用户名和头像

现在我想加入他们的行列计算每个朋友和个人资料所有者之间的共同朋友是否可以在一个查询中做到这一点,或者我应该为每个创建的朋友做一些这样的很长很可能很慢的查询(这只是一个例子,它可能有一些语法错误):

 foreach ($friends_list_query_resul as $qr){ 
     $friend_id = $qr['id']; 

     $mutual_count = mysql_query 
    ("select count(*) from friends_table where 
    ($u1_id = $friend_id || $u2_id = $friend_id) 
       && 


    ($u1_id IN (SELECT `u1_id`,`u2_id` from friends_table where 
    ($u1_id = $profile_id || $u2_id = $profile_id)) 

|| 

     $u2_id IN (SELECT `u1_id`,`u2_id` from friends_table where 
    ($u1_id = $profile_id || $u2_id = $profile_id)) 


     ") 
     } 
+9

不怕大写字母...... – Lix

+0

我的建议是提取每个ID的朋友列表,并用php做出常见的朋友之间的匹配,当涉及操纵数据时,MSQL比其他编程语言慢。 – jcho360

+0

@ jcho360不好的建议。数据库的规模往往比这种内存方式要好得多。数据库在处理数据时不会“比其他编程语言慢”,实际上,如果使用正确的话,它们通常要快得多。 –

回答

0

我已经决定为表中的每个朋友关系添加两行。

id u1_id  u2_id 
1   10   20 
2   20   10 

它使过程更容易和更快。

+1

哇,不知道回答自己的问题是合法的......无论如何,一定要保存谁要求友谊的信息,以防万一你需要它 –

0

首先,我不明白为什么那么复杂的查询,以获得用户的朋友......应该通过这个查询简单地实现:

select u.id, 
    u.username, 
    u.avatar 
from friends_table f 
left join users_table u on f.u2_id = u.id 
where f.u1_id = $profile_id 

说明:登录的用户是其ID的一个与f.u1_id相同。因此,我们只选择其ID为f.u2_id的朋友。

然后,算我的朋友们共同的朋友,我们可以使用这样的查询:

select count(*) as mutual_count, f.u1_id as mutual_friend_id 
from friends_table f 
where f.u1_id IN (select f.u2_id from friends_table where f.u1_id = {$profile_id}) 

其中$ PROFILE_ID是登录用户的ID ...

这是正确的吗?

+0

实际上,关于第一个查询,'$ profile_id'也可以在'f.u2_id'列 – pomeh

+0

是的当然,因为它有很多关系,但是当它在'f.u2_id'中时,它意味着我是某个身份为'f.u1_id'的人的朋友 - 这种关系对我们来说不是问题(或者不应该)只是当我的朋友拿起...而不是我的朋友... – shadyyx

+0

这是不确定的用户!我认为这取决于用例。 @max你觉得怎么样? – pomeh

1

第一个查询也可以写成:

select distinct u.id, 
     u.username, 
     u.avatar 
    from users_table u where u.id in 
     (select case when u1_id=$profile_id then u2_id else u1_id end 
     from friends_table f where case when u1_id=$profile_id 
     then u1_id else u2_id end =$profile_id); 

的共同的朋友查询可以写成类似的时尚单查询:

select u.id, (select count(f.id) from friends f where 
    case when f.u1_id=u.id then u2_id else u1_id end in 
     (select distinct case when u1_id=$profile_id then u2_id else u1_id end 
     from friends where case when u1_id=$profile_id then u1_id else u2_id 
     end =$profile_id) 
    and u1_id=u.id or u2_id=u.id and 
    (u1_id <> $profile_id and u2_id <> $profile_id)) 
as mutual_frnds from user u where u.id <> $profile_id; 

,但你可能要性能测试要么他们之前使用。

+0

我希望不使用子查询来做到这一点。我要检查表现并看看。 thanx重播 – max

1

所有你需要的是一个查询:

select id, username, avatar, -- ... 
(
    select count(*) 
    from friends_table f1 
    inner join friends_table f2 on f1.u2_id = f2.u1_id and f2.u2_id = f1.u1_id 
    where f1.u1_id = users_table.id 
) 
as mutual_friend_count 
from users_table 

子查询的含义是:

给我计数“朋友的朋友”的用户参与的关系,使得第一个朋友关系的目标是第二个朋友关系的来源,第二个朋友关系的目标是第一个朋友关系的来源。

+1

thanx,但我认为这个工作,我不得不改变数据存储在数据库中的方式。现在每个用户都可以在u1_id或u2_id为每个关系,所以我必须检查两个,我不能只是说选择u1_id。 – max

+0

如果你必须指出相互之间的友谊关系,这意味着你所存储的友谊关系并不通勤,即如果你是u2的朋友,这并不意味着你是u1的朋友。如果他们不通勤,那么这个对(u1,u2)与这个对(u2,u1)不是一回事。根据我的看法,friends_table中的一列必须是关系的“来源”,另一列必须是“目标”。我错过了什么? –

+0

事情是友谊通勤。如果我请你成为我的朋友,你接受,你是我的朋友,我是你的朋友。至少这是它在我的代码 – max