我知道这个话题有很多结果,但它们对我没有帮助。
我有一个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
此外,查询将如何查找好友请求?
答案 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
鉴于存在两个元组确定了“真正的朋友”关系,即1
和n
之间的真正朋友关系将由表中的两行表示:{ {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)