从朋友列表中获取真正的朋友

时间:2013-08-20 18:45:18

标签: mysql

我知道这个话题有很多结果,但它们对我没有帮助。

我有一个user1和user2的朋友表。

真正的朋友是user1是user2的朋友,user2是user1的朋友。

朋友请求是user1是user2的朋友。它看起来像这样:

 user1 | user2
 -------------
 1     | 2
 2     | 1
 1     | 3
 3     | 1
 1     | 5

查询怎么能看到真正的#1朋友?

我尝试了这个,但它返回了null:

SELECT user2 FROM friends WHERE user1 = 1 AND user2 = 1

此外,查询将如何查找好友请求?

3 个答案:

答案 0 :(得分:2)

SELECT a.user1 FROM friends AS a JOIN friends AS b
  ON a.user2 = b.user1 AND a.user1 = b.user2
  WHERE a.user2 = ?

其中?表示ID为“原始”用户。

答案 1 :(得分:0)

SELECT user2 FROM friends 
  WHERE user1 = 1 
  AND user2 IN (SELECT user1 from friends where user2 = 1);

答案 2 :(得分:0)

获得此功能的一种方法是使用JOIN操作:

SELECT f.user2
  FROM friends f
  JOIN friends r
    ON r.user1 = f.user2
   AND r.user2 = f.user1
 WHERE f.user1 = 1

鉴于存在两个元组确定了“真正的朋友”关系,即1n之间的真正朋友关系将由表中的两行表示:{ {1}}和(1,n)

连接条件中的谓词限制返回到具有匹配“反向”元组的行的行。

注意:JOIN操作通常比等效的(n,1)IN (subquery)模式表现更好,但小集合的性能差异可以忽略不计。随着更大的集合,性能差异变得明显。

使用EXISTS谓词可以返回等效结果(通常效率较低):

EXISTS (subquery)

或IN谓词:

SELECT f.user2
  FROM friends f
 WHERE f.user1 = 1
   AND EXISTS ( SELECT 1
                  FROM friends r
                 WHERE r.user1 = f.user2
                   AND r.user2 = f.user1
              )

(如果朋友(user1,user2)没有唯一约束,那么JOIN可能会返回一些其他查询可能无法返回的重复行,但没有一个查询保证不返回重复项。如果没有唯一约束,并且您不希望返回任何重复项,那么您可以在任何这些语句的开头的SELECT之后添加DISTINCT关键字,或者在任何这些语句的末尾添加GROUP BY f.user2语句。

为了使结果集更具确定性(即每次运行查询时返回相同的结果),您可以添加ORDER BY子句。 (但是GROUP BY不需要它,因为MySQL隐式在GROUP BY表达式上执行ORDER BY。)


<强>后续

解释如何将此结果与用户表中的名称绑定?谢谢。我如何得到“不真实”的朋友?

要从用户表中获取名称,我们只需将JOIN添加到用户表,假设id是主键列,user1和user2列是用户表的外键...

SELECT f.user2
  FROM friends f
 WHERE f.user1 = 1
   AND f.user2 IN ( SELECT r.user1
                      FROM friends r
                     WHERE r.user2 = f.user1
                  )

“不真实”的朋友将被表示为元组(表中的行)SELECT f.user2 , u.name FROM friends f JOIN user u ON u.id = f.user2 JOIN friends r ON r.user1 = f.user2 AND r.user2 = f.user1 WHERE f.user1 = 1 ,其没有对应的反元组(1,n)。为了找到这些行,我们使用反连接模式,这是一个OUTER连接(从一侧返回所有行加上任何匹配的行),然后是一个排除发现匹配的行的谓词(在一个中检查一个NULL)如果匹配则保证不为null的列是我们如何做到的那样):

这会找到没有匹配(n,1)的所有(1,n)元组:

(n,1)

我们必须翻转它以获得没有匹配SELECT f.user2 , u.name FROM friends f JOIN user u ON u.id = f.user2 LEFT JOIN friends r ON r.user1 = f.user2 AND r.user2 = f.user1 WHERE r.user1 IS NULL AND f.user1 = 1 行的另一侧(n,1)行:

(1,n)