SQL:建议有1度分离的朋友,我的朋友分享超过2个共同的朋友

时间:2015-06-27 10:34:57

标签: mysql sql

我在编写查询时遇到问题,当他们的朋友共享多个朋友时,向我的最终用户推荐朋友。目前正在使用的架构远非最佳,但我的老板坚持认为我不允许改变表结构,即使我告诉他为朋友关系提供2列比一列快得多

我们目前每个友谊都有一对价值观:

friendID  |  Entity_ID1  |  Entity_Id2
   1              2             3
   2              1             4
   3              2             5

我知道对此列进行反转会使我的查询更加简单。到目前为止,我已经设计了以下查询来尝试为用户找到建议的朋友:

  SELECT DISTINCT Entity_Id, Fb_Id, First_Name, Last_Name, Profile_Pic_Url, Last_CheckIn_Place, Category
  FROM entity
  JOIN friends F1
  ON entity.Entity_Id = F1.Entity_Id2 OR entity.Entity_Id = F1.Entity_Id1
  /* Friends of Friends */
  WHERE F1.Entity_Id2 IN
  (
    SELECT Entity_Id1
      FROM friends F
     WHERE F.Entity_Id2 = :userId
       AND F.Category != 4

     UNION

     SELECT Entity_Id2
      FROM friends F
     WHERE F.Entity_Id1 = :userId
       AND F.Category != 4
  )
  /* Exclude my friends */
  AND F1.Entity_Id1 NOT IN
  (
    SELECT Entity_Id1
      FROM friends F
     WHERE F.Entity_Id2 = :userId
       AND F.Category != 4

     UNION

     SELECT Entity_Id2
      FROM friends F
     WHERE F.Entity_Id1 = :userId
       AND F.Category != 4
  )
  /* Exclude self */
  AND F1.Entity_Id1 != :userId
  GROUP BY Entity_Id

  /* Perform again for userId 2 */
  UNION

  SELECT DISTINCT Entity_Id, Fb_Id, First_Name, Last_Name, Profile_Pic_Url, Last_CheckIn_Place, Category
  FROM entity
  JOIN friends F2
  ON entity.Entity_Id = F2.Entity_Id2 OR entity.Entity_Id = F2.Entity_Id1
  WHERE F2.Entity_Id1 IN
  (
    SELECT Entity_Id1
      FROM friends F
     WHERE F.Entity_Id2 = :userId
       AND F.Category != 4

     UNION

     SELECT Entity_Id2
      FROM friends F
     WHERE F.Entity_Id1 = :userId
       AND F.Category != 4
  )
  /* Exclude my friends */
  AND F2.Entity_Id2 NOT IN
  (
    SELECT Entity_Id1
      FROM friends F
     WHERE F.Entity_Id2 = :userId
       AND F.Category != 4

     UNION

     SELECT Entity_Id2
      FROM friends F
     WHERE F.Entity_Id1 = :userId
       AND F.Category != 4
  )
  AND F2.Entity_Id2 != :userId
  GROUP BY Entity_Id

这种作品,然而它返回用户我已经是我不想要的朋友,我想通过为我的朋友使用NOT IN()子句,然后使用UNION合并结果,这将脱掉我的朋友,但显然没有。

我在这里做错了什么,是否有任何方法可以在不修改架构的情况下缩短查询时间,现在它看起来很长而且不易管理。

1 个答案:

答案 0 :(得分:1)

错过互惠关系确实会让事情变得更加艰难。它需要检查关系的两个方向。您似乎正在寻求使用union来重建关系双方的策略。

或者,您可以使用exists和子查询。以下版本使用exists找到不是朋友并且至少有两个朋友的实体:

select e.*
from entities e
where e.entity_id <> :user_id and
      not exists (select 1
                  from friends f
                  where f.category <> 4 and
                        :user_id in (f.entity_id1, f.entity_id2) and
                        e.entity_id in (f.entity_id1, f.entity_id2)
                 ) and
      (select count(*)
       from friends f1 join
            friends f2
            on f1.entity_id1 = f2.entity_id1 or
               f1.entity_id1 = f2.entity_id2 or
               f1.entity_id2 = f2.entity_id1 or
               f1.entity_id1 = f2.entity_id2
       where :user_id in (f1.entity_id1, f1.entity_id2, f2.entity_id1, f2.entity_id2) and
             e.entity_id in (f1.entity_id1, f1.entity_id2, f2.entity_id1, f2.entity_id2)
      ) >= 2

希望您没有太多数据。此版本和您尝试的版本都不会在大量数据上有良好的性能。