Postgres - 连接三个表并对查询中的数据使用聚合函数

时间:2021-05-30 16:43:32

标签: sql postgresql aggregate-functions

我有三张桌子:

帖子:

  id  |  title
------------------
  1   |  post1
  2   |  post2
  3   |  post3
  4   |  post4

评论:

  post_id  |  content
-----------------------
     1     |  asd
     1     |  dsad
     1     |  awtihaw
     2     |  aaaaa
     2     |  bbbbbbbb
     4     |  asdasd

投票:

  post_id  |  value
-----------------------
     1     |  1
     2     |  1
     2     |  -1
     3     |  1
     3     |  1
     3     |  1
     3     |  -1

问题

我需要计算每个帖子有多少评论和多少赞。

这是我的查询:

SELECT posts.id, COUNT(comments.post_id) as comments, SUM(votes.value) as votes
FROM posts
LEFT JOIN comments ON posts.id = comments.post_id
LEFT JOIN votes ON posts.id = votes.post_id
GROUP BY posts.id
ORDER BY posts.id

事实上我得到了一个结果,但是在结果中它说

帖子,id为1,获得3票3条评论

实际上它只有一票和三条评论。 如何正确连接三个表以显示正确的结果?我只需要在查询中执行此操作,最好只在一个查询中执行此操作。

3 个答案:

答案 0 :(得分:1)

一个简单的解决方案是使用相关子查询:

SELECT p.id,
       (SELECT COUNT(*)
        FROM comments c
        WHERE p.id = c.post_id
       ) as num_comments,
       (SELECT SUM(v.value)
        FROM votes v
        WHERE p.id = v.post_id
       ) as net_votes
FROM posts p
ORDER BY p.id;

对于 comments(post_id)votes(post_id, value)posts(id) 上的索引,这可能是最快的解决方案。

答案 1 :(得分:1)

您应该在 commentsvotes 中分别聚合,然后加入 posts

SELECT p.id, c.comments_count, v.votes_sum
FROM posts p
LEFT JOIN (
  SELECT post_id, COUNT(post_id) comments_count
  FROM comments 
  GROUP BY post_id
) c ON p.id = c.post_id
LEFT JOIN (
  SELECT post_id, SUM(value) votes_sum
  FROM votes 
  GROUP BY post_id
) v ON p.id = v.post_id
ORDER BY p.id

对于没有任何评论或投票的帖子,这将返回 NULL
如果您想要 0,请使用 COALESCE()

SELECT p.id, 
       COALESCE(c.comments_count, 0) comments_count, 
       COALESCE(v.votes_sum, 0) votes_sum
FROM .....

答案 2 :(得分:-1)

我认为 JOIN 不是我们应该尝试的方式。

在这里,当我们使用 JOIN 时,对于同一请求的每次投票都会重复对帖子的评论。 同样,每条评论都会重复投票。

在给定的示例中,您仅获得了正确的评论值,因为我们只有一行投票给 POST_ID 1。

我们必须使用 INNER 查询来获得正确的结果,而不是 JOIN。

相关问题