我正在构建一个用户可以相互连接的应用程序(类似于任何社交网络中的朋友)。
我将表中的连接保存在具有以下结构的表中:
id_user1 | id_user2 | is_accepted | is_blocked | created_at
用户之间的连接是双向的,因此当连接两个用户时,表中只有一条记录。如果user_id
位于id_user1
或id_user2
列中,则无关紧要。
现在我需要编写一个sql查询来获取某个用户的“朋友的朋友”,这些朋友不是用户的朋友。 此外,用户必须被接受而不被阻止。
在简历中,以下是我需要执行的步骤。
查找与我想要的用户相关联的所有用户ID(id_user1 = current_user
或id_user2 = current_user
以及is_accepted
和!blocked
)
返回的user_ids的foreach - >获取所有关联用户(忽略与当前用户的关联)(确保它还是accepted
和!blocked
)。
我该如何进行此类查询?。
感谢您的帮助。
答案 0 :(得分:4)
由于其他人提到的原因,并且因为我看到它在其他系统中运行得更好,我会为每个方向选择一行。
primary_user_id | related_user_id | is_accepted | is_blocked | created_at
然后,您还可以在user_id上创建聚簇索引,这应该可以抵消行数加倍的开销。
您的第一个查询将转换为以下内容:
SELECT f1.related_user_id
FROM friends f1
WHERE f1.primary_user_id = @current_user
AND f1.is_accepted = 1 AND f1.is_blocked = 0
AND EXISTS (
SELECT *
FROM friends f2
WHERE f1.related_user_id = f2.primary_user_id
AND f2.related_user_id = @current_user
AND f2.is_accepted = 1 AND f2.is_blocked = 0
不确定您是否可以在MySql中执行表函数。如果是这样,那么将它包装成一个函数,使你的第二个查询更简单。
答案 1 :(得分:2)
SELECT CASE f2.id_user1 WHEN CASE f1.id_user1 WHEN $user THEN f1.id_user2 ELSE f1.id_user1 END THEN f2.id_user2 ELSE f2.id_user1 END
FROM friends f1
JOIN friends f2
ON f2.id_user1 = CASE f1.id_user1 WHEN $user THEN f1.id_user2 ELSE f1.id_user1 END
OR f2.id_user2 = CASE f1.id_user1 WHEN $user THEN f1.id_user2 ELSE f1.id_user1 END
WHERE (f1.id_user1 = $user OR f1.id_user = $user)
AND f1.is_accepted = 1
AND f2.is_accepted = 1
AND f1.is_blocked = 0
AND f2.is_blocked = 0
AND NOT (f1.id_user1, f1.id_user2) = (f2.id_user1, f2.id_user2)
请注意,最好将用户存储在最小的第一个,最大的第二个。在这种情况下,查询会更简单。
答案 2 :(得分:1)
当直接使用one-record-per-friendship表时,所有查询都会变得臃肿且容易出错,因为你必须经常写'id_user1 = ...或id_user2 = ...'。我要创建一个视图
CREATE VIEW bidifreinds (id_user1, id_user2, is_accepted, is_blocked, created_at) AS
SELECT id_user1, id_user2, is_accepted, is_blocked, created_at FROM friends
UNION
SELECT id_user2, id_user1, is_accepted, is_blocked, created_at FROM friends
这将使生活更轻松。
然后你可以写
SELECT f1.id_user1, f2.id_user2
FROM friends f1, friends f2
WHERE f2.id_user1 = f1.id_user2
AND f1.is_accepted
AND NOT f1.is_blocked
AND f2.is_accepted
AND NOT f2.is_blocked
我希望你不是MySQL,因为MySQL查询视图的速度非常慢。
答案 3 :(得分:0)
select id_user1 from friends where is_accepted = 1 and is_blocked = 0 and id_user2 in
(select id_user1 from friends where is_accepted = 1 and is_blocked = 0 and id_user2 = :a_user:
union
select id_user2 from friends where is_accepted = 1 and is_blocked = 0 and id_user1 = :a_user:)
union
select id_user2 from friends where is_accepted = 1 and is_blocked = 0 and id_user1 in
(select id_user1 from friends where is_accepted = 1 and is_blocked = 0 and id_user2 = :a_user:
union
select id_user2 from friends where is_accepted = 1 and is_blocked = 0 and id_user1 = :a_user:)
您可以添加一个Where子句去除:用户:来自结果集。