2012-06-11 53 views
16

The question you're asking appears subjective and is likely to be closed.SQL選擇了你可能認識

當我在上面可怕的警告看到當我在標題字段填寫我並不感到驚訝。

我幾乎讀過所有關於friends of friendsmutual friends的帖子,但我不確定我是否找到了我想要的正確解決方案。

對不起,我不擅長英語和SQL。

如何在兩種語言都不好的情況下找到正確的答案?

我決定我不得不問。我不會因爲down-vote或任何duplication warning而讓自己失望。

正如我想要的答案,我會盡可能真誠地寫下來,因爲任何進一步的類似問題都可以得到幫助。

我有一張朋友關係表。

FRIEND (TABLE) 
----------------------------------- 
PLAYER_ID(PK,FK) FRIEND_ID(PK,FK) 
----------------------------------- 
1     2     // 1 knows 2 
2     1     // 2 knows 1 
1     3     // 1 knows 3 
2     3     // 2 knows 3 
2     4     // 2 knows 4 
2     5     // 2 knows 5 // updated 
3     5     // 3 knows 5 // updated 
1     100 
1     200 
1     300 
100    400 
200    400 
300    400 

兩個composite primary keys也從PLAYER表的外鍵。

我問,並從這麼好的人回答「人們相互認識」。

SQL view for acquaintance from table

我有這樣的看法。

ACQUAINTANCE (VIEW) 
----------------------------------- 
PLAYER_ID(PK,FK) FRIEND_ID(PK,FK) 
----------------------------------- 
1     2     // 1 knows 2 
2     1     // 2 knows 1 

正如您可能會注意到的,這種關係的業務邏輯有以下兩個目的。

  1. 一個玩家可以說他或她知道別人。
  2. 當兩個人都說他們彼此認識時,他們可以說是熟人。

而且,現在,我想知道的是有

  1. 選擇其他PLAYER_IDs
  2. 按照給定的播放器(PLAYER_ID)什麼好的方法(比如1)
  3. 它們各自的一個`給定PLAYER的直接朋友的朋友'
  4. 哪一個不是玩家本人(不包括1 - > 2 - > 1)
  5. 哪一個不是玩家的直接朋友(不包括3個1→2→3→1→3)
  6. 如果可能,按共同朋友的數量排序。

我認爲Justin Niessner在"people you may know" sql query的回答是我必須遵循的最接近的路徑。

在此先感謝。

如果此主題真的重複且不必要,我將關閉該主題。

UPDATE --------------------------------------------- -----------------

爲拉斐爾奧爾索斯的評論whose name is same with my future daughter(是男孩的名字?),

3是一個候選friends of friends of 1因爲

1 knows 2 
2 knows 3 

但排除在外,因爲

1 already knows 3 

基本上我想以服務爲given player

people he or she may know 
which is not himself or herself // this is nothing but obvious 
which each is not already known to himself 

有了上面的表格

by 1 -> 2 -> 4 and 1 -> 3 -> 5 

4 and 5 can be suggested for 1 as 'people you may know' 

order by number of mutual friends will be perfect 
but I don't think I can understand even if someone show me how. sorry. 

謝謝。

UPDATE --------------------------------------------- ------------------------

我想我必須自己從我學過的東西中一步一步地學習FROM HERE WITH VARIOUS PEOPLE即使它不是正確答案。 請讓我知道如果我做錯了什麼。

首先,讓我自己加入FRIEND表本身。

SELECT * 
FROM FRIEND F1 INNER JOIN FRIEND F2 ON F1.FRIEND_ID = F2.PLAYER_ID 

打印

+-----------+-----------+-----------+-----------+ 
| PLAYER_ID | FRIEND_ID | PLAYER_ID | FRIEND_ID | 
+-----------+-----------+-----------+-----------+ 
|   1 |   2 |   2 |   1 | 
|   1 |   2 |   2 |   3 | 
|   1 |   2 |   2 |   4 | 
|   1 |   2 |   2 |   5 | 
|   1 |   3 |   3 |   5 | 
|   2 |   1 |   1 |   2 | 
|   2 |   1 |   1 |   3 | 
|   2 |   3 |   3 |   5 | 
+-----------+-----------+-----------+-----------+ 

F2.FRIEND_ID僅

SELECT F2.FRIEND_ID 
FROM FRIEND F1 INNER JOIN FRIEND F2 ON F1.FRIEND_ID = F2.PLAYER_ID 

打印

+-----------+ 
| FRIEND_ID | 
+-----------+ 
|   1 | 
|   3 | 
|   4 | 
|   5 | 
|   5 | 
|   2 | 
|   3 | 
|   5 | 
+-----------+ 

1只

SELECT F2.FRIEND_ID 
FROM FRIEND F1 INNER JOIN FRIEND F2 ON F1.FRIEND_ID = F2.PLAYER_ID 
WHERE F1.PLAYER_ID = 1; 

打印

+-----------+ 
| FRIEND_ID | 
+-----------+ 
|   1 | 
|   3 | 
|   4 | 
|   5 | 
|   5 | 
+-----------+ 

不是1個

SELECT F2.FRIEND_ID 
FROM FRIEND F1 INNER JOIN FRIEND F2 ON F1.FRIEND_ID = F2.PLAYER_ID 
WHERE F1.PLAYER_ID = 1 
AND F2.FRIEND_ID != 1; 

打印

+-----------+ 
| FRIEND_ID | 
+-----------+ 
|   3 | 
|   4 | 
|   5 | 
|   5 | 
+-----------+ 

不爲1的直接的已知,

SELECT F2.FRIEND_ID 
FROM FRIEND F1 INNER JOIN FRIEND F2 ON F1.FRIEND_ID = F2.PLAYER_ID 
WHERE F1.PLAYER_ID = 1 
AND F2.FRIEND_ID != 1 
AND F2.FRIEND_ID NOT IN (SELECT FRIEND_ID FROM FRIEND WHERE PLAYER_ID = 1); 

打印

+-----------+ 
| FRIEND_ID | 
+-----------+ 
|   4 | 
|   5 | 
|   5 | 
+-----------+ 

我想我到了那裏。

UPDATE --------------------------------------------- --------------------

以下路徑添加

1 -> 100 -> 400 
1 -> 200 -> 400 
1 -> 300 -> 400 

和上次查詢打印(再次)

+-----------+ 
| FRIEND_ID | 
+-----------+ 
|   4 | 
|   5 | 
|   5 | 
|  400 | 
|  400 | 
|  400 | 
+-----------+ 

在最後,我得到了候選人:4,540

distinct當然對於工作的首要目標

SELECT DISTINCT F2.FRIEND_ID 
FROM FRIEND F1 INNER JOIN FRIEND F2 ON F1.FRIEND_ID = F2.PLAYER_ID 
WHERE F1.PLAYER_ID = 1 
AND F2.FRIEND_ID != 1 
AND F2.FRIEND_ID NOT IN (SELECT FRIEND_ID FROM FRIEND WHERE PLAYER_ID = 1); 

打印

+-----------+ 
| FRIEND_ID | 
+-----------+ 
|   4 | 
|   5 | 
|  400 | 
+-----------+ 

而且,現在,通過在需要相互計數訂貨。

這裏是每個候選人的共同朋友的數量。

+-----------+ 
| FRIEND_ID | 
+-----------+ 
|   4 | 1 (1 -> 2 -> 4) 
|   5 | 2 (1 -> 2 -> 5, 1 -> 3 -> 5) 
|  400 | 3 (1 -> 100 -> 400, 1 -> 200 -> 400, 1 -> 300 -> 400) 
+-----------+ 

如何計算和訂購這些共同朋友的數量?

SELECT F2.FRIEND_ID, COUNT(*) 
FROM FRIEND F1 INNER JOIN FRIEND F2 ON F1.FRIEND_ID = F2.PLAYER_ID 
WHERE F1.PLAYER_ID = 1 
AND F2.FRIEND_ID != 1 
AND F2.FRIEND_ID NOT IN (SELECT FRIEND_ID FROM FRIEND WHERE PLAYER_ID = 1) 
GROUP BY F2.FRIEND_ID; 

打印

+-----------+----------+ 
| FRIEND_ID | COUNT(*) | 
+-----------+----------+ 
|   4 |  1 | 
|   5 |  2 | 
|  400 |  3 | 
+-----------+----------+ 

我知道了!

SELECT F2.FRIEND_ID, COUNT(*) AS MFC 
FROM FRIEND F1 INNER JOIN FRIEND F2 ON F1.FRIEND_ID = F2.PLAYER_ID 
WHERE F1.PLAYER_ID = 1 
AND F2.FRIEND_ID != 1 
AND F2.FRIEND_ID NOT IN (SELECT FRIEND_ID FROM FRIEND WHERE PLAYER_ID = 1) 
GROUP BY F2.FRIEND_ID 
ORDER BY MFC DESC; 

打印

+-----------+-----+ 
| FRIEND_ID | MFC | 
+-----------+-----+ 
|  400 | 3 | 
|   5 | 2 | 
|   4 | 1 | 
+-----------+-----+ 

可有人請證實?該查詢是否最優?將它視爲視圖時可能出現任何性能問題?

謝謝。

UPDATE --------------------------------------------- -----------------------------------------------

我創建了一個視圖爲

CREATE VIEW FOLLOWABLE AS 
    SELECT F1.PlAYER_ID, F2.FRIEND_ID AS FOLLOWABLE_ID, COUNT(*) AS MFC 
    FROM FRIEND F1 INNER JOIN FRIEND F2 ON F1.FRIEND_ID = F2.PLAYER_ID 
    WHERE F2.FRIEND_ID != F1.PLAYER_ID 
    AND F2.FRIEND_ID NOT IN (SELECT FRIEND_ID FROM FRIEND WHERE PLAYER_ID = F1.PLAYER_ID) 
    GROUP BY F2.FRIEND_ID 
    ORDER BY MFC DESC; 

並進行了測試。

mysql> select * from FOLLOWABLE; 
+-----------+---------------+-----+ 
| PlAYER_ID | FOLLOWABLE_ID | MFC | 
+-----------+---------------+-----+ 
|   1 |   400 | 3 | 
|   1 |    5 | 2 | 
|   2 |   100 | 1 | 
|   2 |   200 | 1 | 
|   2 |   300 | 1 | 
|   1 |    4 | 1 | 
+-----------+---------------+-----+ 
6 rows in set (0.01 sec) 

mysql> select * from FOLLOWABLE WHERE PLAYER_ID = 1; 
+-----------+---------------+-----+ 
| PlAYER_ID | FOLLOWABLE_ID | MFC | 
+-----------+---------------+-----+ 
|   1 |   400 | 3 | 
|   1 |    5 | 2 | 
|   1 |    4 | 1 | 
+-----------+---------------+-----+ 
3 rows in set (0.00 sec) 
+1

點1 => 3不是我的(差)的眼睛說清楚。你可以提供一組數據和你想要檢索的確切結果,或者(如果你的數據集足夠的話,只是你想要的結果)。 –

+1

您是否期望生成的SQL返回4? –

+2

值得一提的是,您正在應用一種稱爲圖論的數學分支。如果你在這個問題上做的不僅僅是一小撮的工作,你應該明智地閱讀一本關於這個問題的書。它有許多微妙之處。有關如何學習該材料的建議,請嘗試使用programmers.stackexchange.com –

回答

7

使用本 編輯

SELECT `friend_id` AS `possible_friend_id` 
FROM `friends` 
WHERE `player_id` IN (  --selecting those who are known 
    SELECT `friend_id`  --by freinds of #1 
    FROM `friends` 
    WHERE `player_id` = 1) 
AND `friend_id` NOT IN (  --but not those who are known by #1 
    SELECT `friend_id` 
    FROM `friends` 
    WHERE `player_id` = 1) 
AND NOT `friend_id` = 1  --and are not #1 himself 
           --if one is known by multiple people 
           --he'll be multiple time in the list 
GROUP BY `possible_friend_id` --so we group 
ORDER BY COUNT(*) DESC  --and order by amount of repeatings 
+0

謝謝您的回答,主席先生。我瞭解第二和第三個條件。但我很難理解第一個條件。這真的是查詢「朋友的朋友」嗎? –

+0

它是,我選擇所有球員誰是朋友1 – Valerij

+0

所有朋友我很驚訝你的查詢顯示完全一樣的結果與我的加入。謝謝。你能請幾分鐘的時間按照共同朋友的人數排序嗎? –