0

想要 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查询。

4

2 回答 2

2

修改

该查询会将朋友表中一行的“单向”关系视为“双向”关系。也就是说,它会考虑一个朋友关系:('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 在这里http://sqlfiddle.com/#!2/b23a5/2

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


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

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'的共同朋友。


跟进

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

现在听起来好像您希望将该关系表中的一行视为“双向”关系,而不仅仅是“单向”关系。听起来您想考虑将朋友关系 ('abc','xyz') 等同于 ('xyz','abc')。

要做到这一点,需要做的就是让查询创建反向行,这使得查询更容易。我们只需要注意,如果这两个行 ('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 表中的谓词会更简单,但这可能是一个非常大(且成本高昂)的行集来实现。

于 2013-07-17T03:45:59.240 回答
0

尝试这个:

假设您想获得朋友 1 和 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)
于 2013-07-17T13:24:44.880 回答