2013-11-25 86 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 

希望它可以幫助別人,將來