自联接查询以在一个表中获得结果

时间:2014-04-06 16:48:17

标签: mysql outer-join self-join

我有一张如下表格。

+------+----------+--------+
|  id  |sender_id |receiver_id|
+------+----------+--------+
|  1   | 1        | 4      |
|  2   | 1        | 34     |
|  3   | 4        | 1      |
|  4   | 11       | 8      |
|  5   | 24       | 4      |
|  6   | 11       | 5      |
+------+----------+--------+

我希望看到我的结果如下。

+------+----------+--------+
|user_id|sent     |receive  |
+------+----------+--------+
|  1   | 2        | 1      |
|  4   | 1        | 2      |
|  5   | 0        | 1      |
|  8   | 0        | 1      |
| 11   | 2        | 0      |
| 24   | 1        | 0      |
| 34   | 0        | 1      |
+------+----------+--------+

我想在一个表中显示我的结果,其中user_id列(所有唯一的sender_id& receiver_id)为user_id,发送(count(sender_id)为已发送,count(receiver_id))为receive。所以我可以在每个用户发送的一个表中得到一个结果&收到消息号码。 我正在尝试自我加入查询,但没有得到我预期的结果。

2 个答案:

答案 0 :(得分:0)

我会使用此查询:

SELECT user_id, SUM(sent), SUM(receive)
FROM (
  SELECT sender_id AS user_id, COUNT(*) AS sent, 0 AS receive
  FROM tablename
  GROUP BY sender_id
  UNION ALL     
  SELECT receiver_id AS user_id, 0 AS sent, COUNT(*) AS receive
  FROM tablename
  GROUP BY receiver_id
) s
GROUP BY user_id

请参阅小提琴here

答案 1 :(得分:0)

假设您有一个用户表,一种(低效但简洁)的方式是使用相关子查询:

SELECT user_id,
       (SELECT COUNT(*) FROM messages WHERE sender_id   = u.user_id) sent,
       (SELECT COUNT(*) FROM messages WHERE receiver_id = u.user_id) received
FROM   users u

另一种方法是JOIN表并在聚合期间执行计数:

SELECT   u.user_id,
         SUM(m.sender_id   = u.user_id) sent,
         SUM(m.receiver_id = u.user_id) received
FROM     users u JOIN messages m ON u.user_id IN (m.sender_id, m.receiver_id)
GROUP BY u.user_id

第三种(可能是最有效的)方式是首先以两种方式聚合表,然后加入结果:

SELECT user_id, m1.sent, m2.received
FROM   users LEFT JOIN (
         SELECT   sender_id AS user_id, COUNT(*) AS sent
         FROM     messages
         GROUP BY user_id
       ) m1 USING (user_id) LEFT JOIN (
         SELECT   receiver_id AS user_id, COUNT(*) AS received
         FROM     messages
         GROUP BY user_id
       ) m2 USING (user_id)

但是,如果这是您希望经常在大型数据集上进行的操作,则可以考虑在users表中缓存每个用户发送/接收的消息数(并且只需更新一次)发送新邮件。)