【问题标题】:Social network - Suggested friends社交网络 - 推荐的朋友
【发布时间】:2013-11-25 07:51:46
【问题描述】:

我有两个简单的 MySQL 表:用户和关系。

关系表:

user_id int(10) unsigned    NO  PRI     
friend_id   int(10) unsigned    NO  PRI 

(部分)用户表:

id  int(10) unsigned    NO  PRI     
username    varchar(128)    NO

我使用这个查询选择朋友的朋友:

SELECT f2.friend_id, u.username
FROM relations f1
JOIN relations f2 ON f1.friend_id=f2.user_id
LEFT JOIN user u ON u.id = f2.friend_id
WHERE f2.friend_id NOT IN (select friend_id from relations where user_id=@user_id) AND f1.user_id= 2 AND f2.friend_id!= 2

但我还需要获得推荐的朋友...(小组中认识 2 个或更多直接朋友的人),我对此有疑问。什么是获得推荐朋友的好方法(查询,还是我应该使用 PHP?)?

【问题讨论】:

  • 没有。用 MySQL 来做。你如何处理互惠?
  • 嗯..我不...有什么建议可以修改此查询以检查我是否也是我朋友的朋友?

标签: mysql sql


【解决方案1】:

考虑以下...这个例子假设互惠是通过在每个友谊中插入两行来建立的。但是,为简单起见,以下示例并未检查友谊是否得到回报!

 DROP TABLE IF EXISTS friends;

 CREATE TABLE friends
 (initiator VARCHAR(12) NOT NULL
 ,reciprocator VARCHAR(12) NOT NULL
 ,PRIMARY KEY (initiator,reciprocator)
 );

 INSERT INTO friends VALUES 
 ('Adam','Ed'),
 ('Ed','Adam'),
 ('Adam','Ben'),
 ('Ben','Adam'),
 ('Adam','Charlie'),
 ('Charlie','Adam'),
 ('Adam','Dan'),
 ('Dan','Adam'),
 ('Ed','Ben'),
 ('Ben','Ed'),
 ('Ben','Charlie'),
 ('Charlie','Ben'),
 ('Charlie','Dan'),
 ('Dan','Charlie'),
 ('Dan','Fred'),
      ('Fred','Dan'),
 ('Adam','Fred'),
      ('Fred','Adam');

要获得 Ben 的所有“朋友之友”的列表,我们可以这样做...

 SELECT y.reciprocator
   FROM friends x
   JOIN friends y
     ON y.initiator = x.reciprocator
    AND y.reciprocator <> x.initiator
   LEFT
   JOIN friends z
     ON z.reciprocator = y.reciprocator 
    AND z.initiator = x.initiator
  WHERE x.initiator = 'Ben'
    AND z.initiator IS NULL;
 +--------------+
 | reciprocator |
 +--------------+
 | Dan          |
 | Fred         |
 | Dan          |
 +--------------+

如您所见,因为 Dan 是 Adam 和 Charlie(Ben 的两个朋友)的朋友,所以他的名字出现了两次。

因此,要获取 DISTINCT 好友列表,只需包含 DISTINCT 运算符即可。

同样,要获取 Ben 不认识但至少是 Ben 的两个朋友的朋友的个人列表,我们可以这样做...

SELECT y.reciprocator
  FROM friends x
  LEFT
  JOIN friends y
    ON y.initiator = x.reciprocator
   AND y.reciprocator <> x.initiator
  LEFT
  JOIN friends z
    ON z.reciprocator = y.reciprocator
   AND z.initiator = x.initiator
 WHERE x.initiator = 'Ben'
   AND z.initiator IS NULL
 GROUP
    BY y.reciprocator
HAVING COUNT(*) >= 2;
 +--------------+
 | reciprocator |
 +--------------+
 | Dan          |
 +--------------+

可能有几种方法可以处理这个问题的互惠方面,就像有几种方法可以处理互惠本身一样。

一种方法是将上面出现的friends 表替换为一个简单的子查询,例如

SELECT y.reciprocator
  FROM (SELECT a.* FROM friends a JOIN friends b ON b.reciprocator = a.initiator AND b.initiator = a.reciprocator) x

  LEFT
  JOIN (SELECT a.* FROM friends a JOIN friends b ON b.reciprocator = a.initiator AND b.initiator = a.reciprocator) y
    ON y.initiator = x.reciprocator
   AND y.reciprocator <> x.initiator

  LEFT
  JOIN (SELECT a.* FROM friends a JOIN friends b ON b.reciprocator = a.initiator AND b.initiator = a.reciprocator) z
    ON z.reciprocator = y.reciprocator
   AND z.initiator = x.initiator

 WHERE x.initiator = 'Ben'
   AND z.initiator IS NULL
 GROUP
    BY y.reciprocator
HAVING COUNT(*) >= 2; 

【讨论】:

  • 太棒了!感谢您的帮助!
【解决方案2】:

谢谢@Strawberry,太糟糕了,我不能马上使用你的解决方案......我的设计(牛墙)完全不同:

+--------------+--------------+--------------+--------------+
| userId       | friendId     | status       | whatever     | 
+--------------+--------------+--------------+--------------+
| 1            | 3            | request      | Dan          |
| 3            | 6            | active       | 
| 1            | 7            | ignore
+--------------+

No dup 1->2 then 2->1 like

所以我的查询:

    SELECT
        y.friendId,
        COUNT(*) AS totalFriends
    FROM
        `ow_friends_friendship` x
    LEFT JOIN `ow_friends_friendship` y 
                ON y.userId = x.friendId         

    WHERE
        x.userId = xxx
    AND  y.friendId not in (SELECT userId FROM ow_friends_friendship WHERE friendId = xxx)
    AND  y.friendId not in (SELECT friendId  FROM ow_friends_friendship WHERE userId = xxx)

    GROUP BY
        y.friendId
    HAVING
        totalFriends >= 2
    ORDER BY
        totalFriends DESC

希望以后能帮到别人

【讨论】:

    猜你喜欢
    • 2023-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-28
    相关资源
    最近更新 更多