2013-11-25 105 views
1

我有两个简单的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 [email protected]_id) AND f1.user_id= 2 AND f2.friend_id!= 2 

但我也需要得到建议的朋友......(组内知道两个或两个以上直接朋友的人),并且我有这方面的问题。什么是一种好方法(查询,还是应该使用PHP?)来获取推荐的朋友?

+0

不需要使用MySQL。你如何对待互惠? – Strawberry

+0

Whell ..我不...任何建议如何我可以修改这个查询来检查,如果我也是我的朋友的朋友? – PsychoX

回答

5

请考虑以下内容......本示例假设通过每个友谊插入两行来确定往复。然而,为了简单起见,下面的例子并没有检查友谊是否有回报!

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'); 

要获得所有奔的“的朋友 - 的 - 朋友”,我们可以做到这一点的列表...

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   | 
+--------------+ 

正如你所看到的,因为丹是朋友亚当和查理(本的朋友)他的名字出现了两次。

因此,要获得DISTINCT朋友朋友列表,只需包含DISTINCT运算符。

同样,获得个人谁是陌生人本名单,但至少两个本的朋友的朋友,我们可以做到这一点...

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; 
+0

太棒了!感谢您的帮助! – PsychoX

0

感谢@Strawberry,太糟糕了我无法使用您的解决方案了蝙蝠的权利......我的设计(oxwall)是完全不同的:

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

没有DUP 1-> 2则2-> 1像

所以我的查询:

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 

希望它可以帮助别人,将来