繁体   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