GROUPBY 多对多本身

GROUPBY many to many with itself

我有一个用户 table,它与自己有多对多的关系,我想获得具有这种特定关系的所有用户对。问题是,在关系 table 中,我这样存储用户:

+------+---------------+
| User |   relation    |
+------+---------------+
| id   | left_user_id  |
| name | right_user_id |
| ...  | ...           |
+------+---------------+

所以当我做一个基本的

SELECT count(*)
FROM relation LEFT OUTER JOIN user AS user_1 ON user_1.id = relation.left_user_id
              LEFT OUTER JOIN user AS user_2 ON user_2.id = relation.right_user_id 
GROUP BY left_user_id, right_user_id;

我有时会得到同一对的两个结果(例如,有时 (Adam, Eva) 和 (Eva, Adam) 是同一对)。我想要实现的只是一对:(Adam, Eva)。

如何实现?

您可以使用函数 least()greatest():

SELECT count(*)
FROM relation r
LEFT OUTER JOIN user AS user_1 ON user_1.id = r.left_user_id
LEFT OUTER JOIN user AS user_2 ON user_2.id = r.right_user_id 
GROUP BY LEAST(r.left_user_id, r.right_user_id), GREATEST(r.left_user_id, r.right_user_id);

或者在这种情况下您不需要连接:

SELECT count(*)
FROM relation 
GROUP BY LEAST(left_user_id, right_user_id), GREATEST(left_user_id, right_user_id);

left join 应该不是必需的。关键是简单地使用 least()greatest()。那将是:

SELECT LEAST(r.left_user_id, r.right_user_id) as user_id_1,
       GREATEST(r.left_user_id, r.right_user_id) as user_id_2,
       COUNT(*)
FROM relation 
GROUP BY user_id_1, user_id_2;

这种方法的一个警告是结果集中的对可能不在原始数据中——按照那个顺序。所以,如果你在数据中有一次 "Eve"/"Adam",那么它将是 return:"Adam"/"Eve"/1。如有必要,可以解决这个问题。