Postgres - 连接三个表并在查询中对数据使用聚合函数
Postgres - connect three tables and use aggregate functions on data in a query
我有三个表:
帖子:
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
问题
我需要统计每个 post 有多少评论和多少赞。
这是我的查询:
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
实际上我得到了一个结果,但是在结果中说
post,id 为 1 有 3 票 和 3 条评论
实际上它只有一票和三条评论。
如何正确连接三个表以显示正确的结果?我需要能够只在查询中执行此操作,最好只在一个查询中执行此操作。
一个简单的解决方案使用相关子查询:
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)
上的索引,这可能是最快的解决方案。
你应该分别在comments
和votes
聚合然后加入到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
对于没有任何评论或投票的帖子,这将 return NULL
。
如果您想要 0
,请使用 COALESCE()
:
SELECT p.id,
COALESCE(c.comments_count, 0) comments_count,
COALESCE(v.votes_sum, 0) votes_sum
FROM .....
我认为 JOIN 不是我们应该尝试的方式。
在这里,当我们使用 JOIN 时,post 的注释会在同一请求的每次投票结果中重复出现。
同样,每条评论都会重复投票。
在给定的示例中,您得到正确的评论值只是因为我们只有一行 POST_ID 1.
我们必须使用 INNER 查询而不是 JOIN 来获得正确的结果。
我有三个表:
帖子:
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
问题
我需要统计每个 post 有多少评论和多少赞。
这是我的查询:
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
实际上我得到了一个结果,但是在结果中说
post,id 为 1 有 3 票 和 3 条评论
实际上它只有一票和三条评论。 如何正确连接三个表以显示正确的结果?我需要能够只在查询中执行此操作,最好只在一个查询中执行此操作。
一个简单的解决方案使用相关子查询:
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)
上的索引,这可能是最快的解决方案。
你应该分别在comments
和votes
聚合然后加入到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
对于没有任何评论或投票的帖子,这将 return NULL
。
如果您想要 0
,请使用 COALESCE()
:
SELECT p.id,
COALESCE(c.comments_count, 0) comments_count,
COALESCE(v.votes_sum, 0) votes_sum
FROM .....
我认为 JOIN 不是我们应该尝试的方式。
在这里,当我们使用 JOIN 时,post 的注释会在同一请求的每次投票结果中重复出现。 同样,每条评论都会重复投票。
在给定的示例中,您得到正确的评论值只是因为我们只有一行 POST_ID 1.
我们必须使用 INNER 查询而不是 JOIN 来获得正确的结果。