在单向关系表中找到共同的朋友

时间:2013-07-17 03:31:50

标签: mysql

希望mysql查询找到两个朋友之间的共同朋友但是 我以前的单向关系保持用户的友谊。

首先是用户表

id  name
1   abc
2   xyz
3   pqr

现在第二张桌子是朋友

id user_id friend_id
1   1      2
2   1      3
3   2      3

现在我可以说abc(id = 1)是xyz(id = 2)的朋友,现在类似于xyz是abc的朋友,但现在我想找到abc(id = 1)和xyz之间的共同朋友(id = 2)那是pqr所以我想要mysql查询。

2 个答案:

答案 0 :(得分:2)

<强> REVISED

此查询将把friend表中某行的“单向”关系视为“双向”关系。也就是说,它会考虑朋友关系:('abc','xyz')等同于反向关系:('xyz','abc')。 (注意:我们不保证两行都不会出现在表格中,因此我们需要注意这一点。UNION运算符可以方便地为我们删除重复项。)

此查询应符合规范:

SELECT mf.id
     , mf.name
  FROM (
         SELECT fr.user_id AS user_id
              , fr.friend_id AS friend_id
           FROM friend fr
           JOIN users fru
             ON fru.id = fr.user_id
          WHERE fru.name IN ('abc','xyz')
          UNION
         SELECT fl.friend_id AS user_id
              , fl.user_id AS friend_id
           FROM friend fl
           JOIN users flf
             ON flf.id = fl.friend_id
          WHERE flf.user IN ('abc','xyz')
       ) f
  JOIN users mf
    ON mf.id = f.friend_id
 GROUP BY mf.id, mf.name
HAVING COUNT(1) = 2
 ORDER BY mf.id, mf.name

SQL Fiddle here http://sqlfiddle.com/#!2/b23a5/2

下面给出了我们如何达到这一点的更详细解释。下面的原始查询假设朋友表中的一行表示“单向”关系,因为“'abc' ff 'xyz'”并不表示“'xyz' ff 'abc'”。但OP的其他评论暗示情况并非如此。


如果friend(user_id,friend_id)上有唯一约束,那么获​​得结果的一种方法是获取每个用户的所有朋友,并获得该朋友的行数。如果计数为2,那么我们知道用户'abc'和'xyz'都会显示特定的friend_id

SELECT mf.id
     , mf.name
  FROM friend f
  JOIN users uu
    ON uu.id = f.user_id
  JOIN users mf
    ON mf.id = f.friend_id
 WHERE uu.name IN ('abc','xyz')
 GROUP BY mf.id, mf.name
HAVING COUNT(1) = 2
 ORDER BY mf.id, mf.name

(此方法还可以扩展为通过在IN列表中包含更多用户,并更改我们将COUNT(1)与之比较的值来查找三个或更多用户的共同朋友。

这不是唯一会返回指定结果集的查询;还有其他方法可以获得它。


获得等效结果的另一种方法:

SELECT u.id
     , u.name
  FROM ( SELECT f1.friend_id
           FROM friend f1
           JOIN users u1
             ON u1.id = f1.user_id
          WHERE u1.name = 'abc'
       ) t1
  JOIN ( SELECT f2.friend_id
           FROM friend f2
           JOIN users u2
             ON u2.id = f2.user_id
          WHERE u2.name = 'xyz'
       ) t2
    ON t2.friend_id = t1.friend_id
  JOIN users u
    ON u.id = t1.friend_id
 ORDER BY u.id, u.name

备注

这些查询不检查用户'abc'是否是'xyz'的朋友(WHERE子句中指定的两个用户名)。它只找到'abc'和'xyz'的共同朋友。


<强>后续

上述查询满足指定的要求,以及问题中提供的所有示例和测试用例。

现在听起来好像你希望那个关系表中的一行被认为是“双向”关系,而不仅仅是“单向”关系。听起来你想要考虑相当于('xyz','abc')的朋友关系('abc','xyz')。

要实现这一点,那么所有需要做的就是让查询创建反向行,这样可以更容易查询。我们只需要小心,如果这些行('abc','xyz')和('xyz','abc')已经存在,那么当我们反转它们时,我们不会创建它们的重复。

要创建反向行,我们可以使用这样的查询。 (当我们没有JOIN到users表时,查看这个更简单,我们只使用id值:

SELECT fr.user_id
     , fr.friend_id 
  FROM friend fr
 WHERE fr.user_id IN (1,2)
 UNION
SELECT fl.friend_id AS user_id
     , fl.user_id AS friend_id
  FROM friend fl
 WHERE fl.friend_id IN (1,2)

如果我们不在user_id和friend_id表中包含谓词,这会更简单,但这可能是一个非常大(且昂贵)的行集来实现。

答案 1 :(得分:0)

试试这个:

鉴于你想要得到朋友的共同朋友1&amp; 2

select friend_id into #tbl1 from users where user_id = 1

select friend_id into #tbl2 from users where friend_id = 2

select id, name from users where id in(select friend_id from #tbl1 f1, #tbl2 f2 where f1.friend_id=f2.friend_id)