一尘不染

分离度查询

sql

我有一个成员对成员连接表。模式为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则处于待处理状态。我需要以我的活跃朋友及其活跃朋友等作为该查询的基础。我的朋友没有一个活跃朋友是我的活跃朋友。

我该如何构造这样的查询(即使我无法显示分离级别并且只能得到相互计数)?现在,我可以想一想,但是它涉及到一些嵌套循环的查询,是的,我只是无法想象对服务器的整体性能或运行状况有什么好处。


阅读 202

收藏
2021-03-10

共1个答案

一尘不染

这是使用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
2021-03-10