【问题标题】:Problems with multiple joins and a sum多个连接和总和的问题
【发布时间】:2021-01-31 11:25:26
【问题描述】:

如果有以下三个PostgreSQL表:

发布表:

postid | title | author | created

投票表:

postid | username | vote

如果用户对帖子投了赞成票,则 vote 等于 1,如果用户没有投票,则为 0,如果用户对帖子投反对票,则为 -1。

评论表:

commentID | parentID | postID | content | author | created

如果评论不是回复,则 parentID 为 null。

我想现在收到每个帖子的标题、作者、创建日期、所有投票的总和以及 当前登录用户的投票和 cmets 的数量。 我已经对用户的投票有疑问,并询问了here,有人帮我得到了以下查询:

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 来获取这样的 cmets 数量:

COUNT(DISTINCT comments) FILTER (WHERE comments.parentID IS NULL) as numComments
LEFT JOIN comments on post.postID = comments.postID

但是,虽然 cmets 的数量有效,但每个帖子的投票数是错误的,因为 由于另一个连接,这些行似乎多次出现,产生了错误的总和,我在想办法解决这个问题时遇到了一些麻烦。

我已经尝试将 cmets 的数量作为子查询获取,以便它独立于 没有成功的票数。 任何进一步的帮助将不胜感激! :-)

【问题讨论】:

    标签: sql postgresql sum inner-join sql-null


    【解决方案1】:

    分别计算值。 joins 导致笛卡尔积。这是相关子查询或横向连接有帮助的地方:

    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;
    

    【讨论】:

      【解决方案2】:

      您通常会在加入之前预先聚合子查询,如下所示:

      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
      

      【讨论】:

      • 如果数据库需要完整的组,这将不起作用。您需要通过 postID、投票、用户名加入。
      猜你喜欢
      • 2016-01-23
      • 2022-10-01
      • 2021-03-22
      • 2015-04-04
      • 2017-05-07
      • 2017-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多