簡體   English   中英

MySQL Query查找朋友和共同朋友的數量

[英]MySQL Query to find friends and number of mutual friends

我已經查看了問題,但我找不到任何完全符合我需要的東西,我無法弄清楚如何自己做。

我有2個表,一個用戶表和一個朋友鏈接表。 用戶表是我所有用戶的表:

    +---------+------------+---------+---------------+
    | user_id | first_name | surname |     email     |
    +---------+------------+---------+---------------+
          1         joe       bloggs    joe@test.com
          2         bill      bloggs    bill@test.com
          3         john      bloggs    john@test.com
          4         karl      bloggs    karl@test.com

我的朋友鏈接表然后顯示用戶之間的所有關系,例如:

    +--------=+---------+-----------+--------+
    | link_id | user_id | friend_id | status |
    +---------+---------+-----------+--------+
       1         1          3           a
       2         3          1           a
       3         4          3           a
       4         3          4           a
       5         2          3           a
       6         3          2           a

作為注釋,狀態欄中的a表示已批准,也可能有r(請求)和d(拒絕)。

我想要做的是查詢如果用戶進行搜索,它將返回他們當前不是朋友的用戶列表以及每個用戶與他們有多少共同朋友。

我已設法獲取當前不與他們成為朋友的所有用戶的查詢。 因此,如果執行搜索的用戶的用戶ID為1:

SELECT u.user_id,u.first_name,u.surname
FROM users u
    LEFT JOIN friend_links fl
        ON u.user_id = fl.user_id AND 1 IN (fl.friend_id)
WHERE fl.friend_id IS NULL
AND u.user_id != 1
AND surname LIKE 'bloggs'

那么我如何計算每個返回用戶的共同朋友數?

編輯:

就像編輯一樣,我不認為我對我的問題特別清楚。

我上面的查詢將產生以下結果集:

    +---------+------------+---------+
    | user_id | first_name | surname |
    +---------+------------+---------+
          2         bill      bloggs
          4         karl      bloggs

這些是與姓氏博客匹配的用戶,這些博客目前不是joe bloggs(用戶ID 1)的朋友。

然后我希望這些用戶中有多少共同的朋友與進行搜索的用戶有關,因此返回的結果如下所示:

    +---------+------------+---------+--------+
    | user_id | first_name | surname | mutual |
    +---------+------------+---------+--------+
          2         bill      bloggs     1
          4         karl      bloggs     1

每個返回的用戶都有1個共同的朋友,因為joe bloggs(用戶ID 1)是john bloggs的朋友,john bloggs是兩個返回用戶的朋友。

我希望這更清楚一點。

謝謝。

可以通過在friend_id字段上將friend_links表連接到自身來找到相互朋友,如下所示:

SELECT *
FROM friend_links f1 INNER JOIN friend_links f2
  ON f1.friend_id = f2.friend_id
WHERE f1.user_id = $person1
  AND f2.user_id = $person2

但請記住,在最糟糕的情況下,這基本上是對friend_links表中的行數進行平方 ,並且一旦您擁有非平凡的行數,就可以非常輕松地將服務器填滿。 更好的選擇是為每個用戶使用2個子查詢,然后加入這些子查詢的結果。

SELECT *
FROM (
  SELECT *
  FROM friend_links
  WHERE user_id = $person1
) p1 INNER JOIN (
  SELECT *
  FROM friend_links
  WHERE user_id = $person1
) p2
  ON p1.friend_id = p2.friend_id

此外,您可以通過刪除代理鍵link_id並僅將(user_id,friend_id)作為主鍵來簡化您的friend_links表,因為它們必須是唯一的。


編輯:

如何將此應用於搜索不是朋友的用戶的原始查詢,如果可能,我想在單個查詢中同時執行這兩項操作?

SELECT f2.user_id, COUNT(*) 'friends_in_common'
FROM friend_links f1 LEFT JOIN friend_links f2
  ON f1.friend_id = f2.friend_id
WHERE f1.user_id = $person
GROUP BY f2.user_id
ORDER BY friends_in_common DESC
LIMIT $number

我也在考慮user_id約束可以從WHERE子句移動到JOIN條件,以減少自連接創建的數據集的大小,並排除使用子查詢,如我的第二個示例。

此查詢列出了與用戶1不是朋友且姓氏與'%bloggs%'匹配'%bloggs%'任何人:

SELECT
  users.user_id,
  users.first_name,
  users.surname,
  Sum(IF(users.user_id = friend_links_1.friend_id, 1, 0)) As mutual
FROM
  users inner join
    (friend_links INNER JOIN friend_links friend_links_1
     ON friend_links.friend_id = friend_links_1.user_id)
  ON friend_links.user_id=1 AND users.user_id<>1
WHERE
  users.surname LIKE '%bloggs%'
GROUP BY
  users.user_id, users.first_name, users.surname
HAVING
  Sum(IF(users.user_id = friend_links.friend_id, 1, 0))=0

只需更改ON子句上的用戶ID,以及WHERE子句上的姓氏。 我認為它現在應該正常工作!

如果A是B的朋友,那么B也是A的朋友? 使用一個鏈接而不是兩個鏈接(而不是在friends_links中的兩行)不是更好嗎? 然后你必須使用兩個狀態列,status1和status2,只有當status1 = status2 =“a”時,A才是B的朋友。

有很多方式可以展示共同的朋友,例如:

SELECT friend_id
FROM friend_links
WHERE friend_links.user_id = $user1 or friend_links.user_id = $user2
  AND NOT (friend_links.friend_id = $user1 or friend_links.friend_id = $user2)
GROUP BY friend_id
HAVING Count(*)>1

此查詢顯示每個用戶和任何不是他/她的朋友的人:

SELECT
  users.user_id,
  users.first_name,
  users_1.user_id,
  users_1.first_name
FROM
  users INNER JOIN users users_1 ON users.user_id <> users_1.user_id
WHERE
  NOT EXISTS (SELECT *
              FROM friend_links
              WHERE
                friend_links.user_id = users.user_id
                AND friend_links.friend_id = users_1.user_id)

(唯一認為我沒有檢查的是友誼狀態,但很容易添加該檢查)。

我還在努力,但要將這兩個查詢很好地結合起來並不容易。 所以這不是一個答案,我只是展示了我嘗試過的一些想法。

但你到底需要什么? 一個查詢,返回每個用戶,不是他/她的朋友和共同的朋友數,或者已經給出了user_id?

使用一些代碼來回答你的問題並不是一個問題...但只需使用SQL就可以有一個很好的方法! :)

編輯:

我仍然想知道是否有更好的解決方案,特別是下一個查詢可能會非常慢,但看起來這可能會起作用:

SELECT
  users_1.user_id,
  users_2.user_id,
  Sum(IF(users_1.user_id = friend_links.user_id AND users_2.user_id = friend_links_1.friend_id, 1, 0)) As CommonFriend
FROM
  users users_1 INNER JOIN users users_2
    ON users_1.user_id <> users_2.user_id,
  (friend_links INNER JOIN friend_links friend_links_1
    ON friend_links.friend_id = friend_links_1.user_id)
GROUP BY
  users_1.user_id,
  users_2.user_id
HAVING
  Sum(IF(users_1.user_id = friend_links.user_id AND users_2.user_id = friend_links.friend_id, 1, 0))=0

(和以前一樣,我沒有檢查友誼狀態)

如果給出了用戶,你可以把WHERE users_1.user_id=$user1放在最好只留下一個用戶表,並過濾掉那個用戶的下一個INNER JOIN。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM