多个连接和求和的问题
Problems with multiple joins and a sum
如果有以下三个PostgreSQL tables:
Post table:
postid | title | author | created
投票table:
postid | username | vote
如果用户投票 post 赞成,则投票等于 1,如果用户未投票则投票等于 0,如果用户投票 post 反对则投票等于 -1。
评论table:
commentID | parentID | postID | content | author | created
如果评论不是回复,parentID 为 null。
我现在想收到每个 post 的标题、作者、创建日期、所有投票的总和以及
当前登录用户的投票和评论数。
我已经对用户的投票有问题并询问 并且有人帮助我得到以下查询:
SELECT post.postID as postID, post.title as title, post.author as author,
post.created as created,
COALESCE(sum(votes.vote), 0) as voteCount,
COALESCE(sum(votes.vote) FILTER (WHERE votes.username = :username), 0) as userVote
FROM post
LEFT JOIN votes ON post.postID = votes.postID
GROUP BY post.postID
ORDER BY voteCount DESC
现在我尝试了另一个 LEFT JOIN
来获取这样的评论数:
COUNT(DISTINCT comments) FILTER (WHERE comments.parentID IS NULL) as numComments
LEFT JOIN comments on post.postID = comments.postID
然而,虽然评论数量有效,但每个 post 的投票数量是错误的,因为
由于另一个连接,这些行似乎多次出现,产生了错误的总和,我在想出解决这个问题的方法时遇到了一些麻烦。
我已经尝试将评论数作为子查询获取,这样它就独立于
未成功的投票数。
任何进一步的帮助将不胜感激! :-)
分别计算值。 join
s 导致笛卡尔积。这是相关子查询或横向连接帮助的地方:
SELECT p.*, v.*, c.*
FROM post p CROSS JOIN LATERAL
(SELECT SUM(v.vote) as voteCount,
SUM(v.vote) FILTER (WHERE v.username = :username), 0) as userVote
FROM votes v
WHERE p.postID = v.postID
) v CROSS JOIN LATERAL
(SELECT SUM(c.vote) as commentCount,
SUM(c.vote) FILTER (WHERE c.username = :username), 0) as userVote
FROM comments c
WHERE p.postID = c.postID
) c
ORDER BY voteCount DESC;
您通常会在加入之前在子查询中 pre-aggregate,如下所示:
SELECT p.*
COALESCE(v.voteCount, 0) as voteCount,
COALESCE(v.userVote, 0) as userVote,
COALESCE(c.numComments, 0) as numComments
FROM post p
LEFT JOIN (
SELECT postID,
SUM(vote) as voteCount,
SUM(vote) FILTER (WHERE username = :username) userVote
FROM votes
GROUP BY postID
) v ON v.postID = p.postID
LEFT JOIN (
SELECT postID, count(*) numComments
FROM comments
WHERE parentID IS NULL
GROUP BY postID
) c ON c.postID = p.postID
ORDER BY voteCount DESC
如果有以下三个PostgreSQL tables:
Post table:
postid | title | author | created
投票table:
postid | username | vote
如果用户投票 post 赞成,则投票等于 1,如果用户未投票则投票等于 0,如果用户投票 post 反对则投票等于 -1。
评论table:
commentID | parentID | postID | content | author | created
如果评论不是回复,parentID 为 null。
我现在想收到每个 post 的标题、作者、创建日期、所有投票的总和以及
当前登录用户的投票和评论数。
我已经对用户的投票有问题并询问
SELECT post.postID as postID, post.title as title, post.author as author,
post.created as created,
COALESCE(sum(votes.vote), 0) as voteCount,
COALESCE(sum(votes.vote) FILTER (WHERE votes.username = :username), 0) as userVote
FROM post
LEFT JOIN votes ON post.postID = votes.postID
GROUP BY post.postID
ORDER BY voteCount DESC
现在我尝试了另一个 LEFT JOIN
来获取这样的评论数:
COUNT(DISTINCT comments) FILTER (WHERE comments.parentID IS NULL) as numComments
LEFT JOIN comments on post.postID = comments.postID
然而,虽然评论数量有效,但每个 post 的投票数量是错误的,因为 由于另一个连接,这些行似乎多次出现,产生了错误的总和,我在想出解决这个问题的方法时遇到了一些麻烦。
我已经尝试将评论数作为子查询获取,这样它就独立于 未成功的投票数。 任何进一步的帮助将不胜感激! :-)
分别计算值。 join
s 导致笛卡尔积。这是相关子查询或横向连接帮助的地方:
SELECT p.*, v.*, c.*
FROM post p CROSS JOIN LATERAL
(SELECT SUM(v.vote) as voteCount,
SUM(v.vote) FILTER (WHERE v.username = :username), 0) as userVote
FROM votes v
WHERE p.postID = v.postID
) v CROSS JOIN LATERAL
(SELECT SUM(c.vote) as commentCount,
SUM(c.vote) FILTER (WHERE c.username = :username), 0) as userVote
FROM comments c
WHERE p.postID = c.postID
) c
ORDER BY voteCount DESC;
您通常会在加入之前在子查询中 pre-aggregate,如下所示:
SELECT p.*
COALESCE(v.voteCount, 0) as voteCount,
COALESCE(v.userVote, 0) as userVote,
COALESCE(c.numComments, 0) as numComments
FROM post p
LEFT JOIN (
SELECT postID,
SUM(vote) as voteCount,
SUM(vote) FILTER (WHERE username = :username) userVote
FROM votes
GROUP BY postID
) v ON v.postID = p.postID
LEFT JOIN (
SELECT postID, count(*) numComments
FROM comments
WHERE parentID IS NULL
GROUP BY postID
) c ON c.postID = p.postID
ORDER BY voteCount DESC