“朋友的朋友”喜欢sql查询

时间:2011-04-26 16:09:56

标签: mysql sql

我正在构建一个用户可以相互连接的应用程序(类似于任何社交网络中的朋友)。

我将表中的连接保存在具有以下结构的表中:

id_user1 | id_user2 | is_accepted | is_blocked | created_at

用户之间的连接是双向的,因此当连接两个用户时,表中只有一条记录。如果user_id位于id_user1id_user2列中,则无关紧要。

现在我需要编写一个sql查询来获取某个用户的“朋友的朋友”,这些朋友不是用户的朋友。 此外,用户必须被接受而不被阻止。

在简历中,以下是我需要执行的步骤。

  1. 查找与我想要的用户相关联的所有用户ID(id_user1 = current_userid_user2 = current_user以及is_accepted!blocked

  2. 返回的user_ids的foreach - >获取所有关联用户(忽略与当前用户的关联)(确保它还是accepted!blocked)。

  3. 我该如何进行此类查询?。

    感谢您的帮助。

4 个答案:

答案 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子句去除:用户:来自结果集。

相关问题