我有一个成员对成员连接表。模式为member_id,friend_id,is_active。我想建立一个成为朋友朋友的成员的成员关系列表。我不太确定如何解决该查询,更不用说以半优化的方式了。
上表的工作方式是,member_id和friend_id在另一张表上本质上是同一件事。在我的系统中,除此一张表外,这些ID通常称为member_id。例如,假设我的member_id是21。我的号码可以在无数其他行上,例如member_id或friend_id,这取决于最初发起实际友谊请求的人,而我并不想在其中重复数据我会伪装成行来基本上做同样的事情。
我想查询一个查询,我不仅可以确定学位程度(例如LinkedIn),还可以确定一个人可能会显示多少个共同的朋友(例如Facebook)。这里的x因子是我前面提到的is_active列。该列可以为0或1。这是一个简单的tinyint列,用作on / off开关。任何具有1的朋友连接都将是活跃的友谊,而0则处于待处理状态。我需要以我的活跃朋友及其活跃朋友等作为该查询的基础。我的朋友没有一个活跃朋友是我的活跃朋友。
我该如何构造这样的查询(即使我无法显示分离级别并且只能得到相互计数)?现在,我可以想一想,但是它涉及到一些嵌套循环的查询,是的,我只是无法想象对服务器的整体性能或运行状况有什么好处。
这是使用JOIN使用广度优先,最短路径搜索执行搜索的方法。该算法没有魔术,因为我们使用MySQL来找到答案,并且没有合并任何使用任何启发式或优化方法的奇特搜索算法。
我的“朋友”表具有单向关系,因此从“ 1到2”和“ 2到1”都存储的意义上讲,我们确实有重复项。我也排除了is_active,因为实现很明显:
数据如下:
member_id friend_id 1 2 1 3 1 4 2 1 2 3 2 5 2 6 3 2 3 1 4 1 5 2 6 2 6 7 7 6 7 8 8 7
我们选择了1位成员,我们问的是1位朋友和7位朋友,还是一位朋友,等等?计数为0表示不,计数为1表示是。
SELECT COUNT(*) FROM friends f1 WHERE f1.member_id = 1 AND f1.friend_id = 7
如果否,那么他们是朋友的朋友吗?
SELECT COUNT(*) FROM friends f1 JOIN friends f2 ON f2.member_id = f1.friend_id WHERE f1.member_id = 1 AND f2.friend_id = 7
如果没有,那么一个朋友的一个朋友呢?
SELECT COUNT(*) FROM friends f1 JOIN friends f2 ON f2.member_id = f1.friend_id JOIN friends f3 ON f3.member_id = f2.friend_id WHERE f1.member_id = 1 AND f3.friend_id = 7
等等…
第三个查询将找到路径“ 1到2”,“ 2到6”和“ 6到7”,返回计数1。
每个查询都变得更加昂贵(由于连接数量更多),因此您可能希望在某些时候限制搜索。一件很酷的事情是,这种搜索从两端到中间都有效,这是为最短路径搜索建议的一种简单优化。
以下是找到会员1的共同朋友推荐的方法:
SELECT f2.friend_id FROM friends f1 JOIN friends f2 ON f2.member_id = f1.friend_id LEFT JOIN friends f3 ON f3.member_id = f1.member_id AND f3.friend_id = f2.friend_id WHERE f1.member_id = 1 AND f2.friend_id <> f1.member_id // Not ourself AND f3.friend_id IS NULL // Not already a friend