如何为“你可能认识的人”(朋友的朋友)创建MySQL查询?

时间:2012-11-24 10:24:25

标签: mysql

我有以下表格:

members(id, name, surname, username, password)
friends(uid, friend_uid, confirmed_uid, confirmed_friend_uid)
朋友表中的

uidfriend_uidmembers.id相关,其中uid始终低于friend_uid。当friends.confirmed同意成为朋友时friends.uid为真,friends.friend_confirmed确认友情时friends.friend_uid为真。

用户A只是B和C的朋友,他们都确认了友谊。我想要一个查询,显示一个B和C的列表(所有已确认的朋友)确认的朋友,他们不是A的朋友。确保如果B和C有共同的朋友,他们就是列表的首位。

由于我的MySQL非常生疏,我目前正在使用多个查询,但这必须非常低效,我需要在它开始影响我的网站性能之前为我创建一个查询。

我已经开始阅读MySQL文档,如果我到达任何地方,我会更新它,但是如果有人可以帮助我加快这个过程,我将非常感激。

以下是我使用一些伪代码进行的操作:

member_id_for_A = 1;
friends_of_A = mysql_query("
            SELECT m.*, f.* FROM friends f 
            inner join members m on m.id = f.uid 
              WHERE f.friend_uid = " + member_id_for_A + " AND confirmed_uid=1 AND confirmed_friend_uid=1 
            UNION
              SELECT m.*, f.* FROM friends f 
              inner join members m on m.id = f.friend_uid 
                WHERE f.uid = " + member_id_for_A + " AND confirmed_uid=1 AND confirmed_friend_uid=1");

foreach(row : friends_of_A)
{
  friend_id = get_friened_id(row, member_id_for_A);
  friends_of_friend = get_friends(friend_id); // Performs a query like above friends_of_friend
  result = remove_matches(friends_of_A, friends_of_friend); // Remove common friends

  // Do something with results and move onto the next friend
}

我知道这是非常糟糕的代码并且效率不高,但这是一种快速的hacky方式,我可以获得我需要的功能,直到我有时间学习更多MySQL。希望它通过单个查询清楚地展示了我的目标。

2 个答案:

答案 0 :(得分:0)

你去......

select m.id,m.surname,m.name from friends f1
inner join friends f2
on f1.friend_uid=f2.uid      /* Identify friend of friend*/
inner join members m
on m.id=f2.friend_uid       /* Match & get Friend of Friend's User detail */
where f1.confirmed_uid=1         /* Friend1 is confirmed */
and f2.confirmed_friend_uid=1
and m.id <> f2.uid          /* Friend2 is not already a friend */

在选择列表中,选择所需字段

答案 1 :(得分:0)

看了subquery documentation后,我设法提出了一个有效的解决方案。

在此示例中,A有一个members.id=8

SELECT * FROM members
WHERE id IN ( 
 SELECT m.id FROM friends f  INNER JOIN members m on m.id=f.uid 
 WHERE f.friend_uid IN ( 
  SELECT m.id FROM friends f  INNER JOIN members m on m.id=f.uid 
  WHERE f.friend_uid=8 AND confirmed_uid=1 AND confirmed_friend_uid=1  
   UNION SELECT m.id FROM friends f  INNER JOIN members m on m.id=f.friend_uid 
   WHERE f.uid=8 AND confirmed_uid=1 AND confirmed_friend_uid=1
 ) AND m.id<>8 AND f.confirmed_uid=1 AND f.confirmed_friend_uid=1 
  UNION SELECT m.id FROM friends f  INNER JOIN members m on m.id=f.uid 
  WHERE f.uid IN ( 
   SELECT m.id FROM friends f INNER JOIN members m on m.id=f.uid 
   WHERE f.friend_uid=8 AND confirmed_uid=1 AND confirmed_friend_uid=1 
    UNION SELECT m.id FROM friends f  INNER JOIN members m on m.id=f.friend_uid
    WHERE f.uid=8 AND confirmed_uid=1 AND confirmed_friend_uid=1
   ) AND m.id<>8 AND f.confirmed_uid=1 AND f.confirmed_friend_uid=1
) AND id NOT IN (
 SELECT m.id FROM friends f  INNER JOIN members m on m.id=f.uid 
 WHERE f.friend_uid=8 AND confirmed_uid=1 AND confirmed_friend_uid=1  
  UNION SELECT m.id FROM friends f  INNER JOIN members m on m.id=f.friend_uid 
  WHERE f.uid=8 AND confirmed_uid=1 AND confirmed_friend_uid=1
); 

此查询运行良好且快速,并返回所有A的朋友的朋友,他们不是A的朋友。它还确保两个成员在关系中确认了友谊。

可能有办法减少此查询的大小,因为整个查询中三个不同的场合使用相同的subquery

 SELECT m.id FROM friends f  INNER JOIN members m on m.id=f.uid 
 WHERE f.friend_uid=8 AND confirmed_uid=1 AND confirmed_friend_uid=1  
  UNION SELECT m.id FROM friends f  INNER JOIN members m on m.id=f.friend_uid 
  WHERE f.uid=8 AND confirmed_uid=1 AND confirmed_friend_uid=1

如果有办法只运行一次子查询,请告诉我。否则,如果/当我自己弄明白时,我会编辑答案。