MySQL:需要return票数最多的前3名用户。两个子查询的 SUM 中的一列中需要的结果。 Java/SpringMVC

MySQL: Needing to return top 3 Users with the most votes. Results wanted in one column from the SUM of two subqueries. Java/Spring MVC

我有一个 Spring MVC 博客,具有 Post 和评论投票功能。我想 return 根据他们在所有帖子和评论中收到的投票数排名前 3 位的用户。

表:

users u [id, username]

posts p [id, u.id]

comments c [id, p.id, u.id]

post_votes pv [p.id, u.id, type (1 or -1)]

comment_votes cv [c.id, u.id, type (1 or -1)]

以下语句通过查询两个单独的投票表然后将总数相加,得到每个用户的总票数:

SELECT
  (SELECT SUM(type) 
  FROM posts_votes pv 
  JOIN posts p ON p.id = pv.post_id 
  JOIN users u ON u.id = p.user_id  
  WHERE u.id LIKE ?1)
+
  (SELECT SUM(type) 
  FROM comments_votes cv  
  JOIN comments c ON c.id = cv.comment_id 
  JOIN users u ON u.id = c.user_id 
  WHERE u.id LIKE ?1)

对于每个用户 ID 的 WHERE 子句,这可以很好地工作...但现在我试图找到投票最多的前 3 名用户,但我遇到了太多困难。这是我目前所拥有的:

 SELECT u.id, u.username, IFNULL(SUM(pv.type), 0) AS totalPostVotes
 FROM posts_votes pv
 JOIN posts p ON p.id = pv.post_id
 JOIN users u ON u.id = p.user_id
 GROUP BY u.id ORDER BY totalPostVotes DESC LIMIT 3

上面的陈述本身就有效,给我:u.id、u.username 和总计 Post 按降序投票。下面的评论也是如此:

 SELECT u.id, u.username, IFNULL(SUM(cv.type), 0) AS totalCommentVotes
 FROM comment_votes cv
 JOIN comments c ON c.id = cv.comment_id
 JOIN users u ON u.id = c.user_id
 GROUP BY u.id ORDER BY totalCommentVotes DESC LIMIT 3

太棒了!但我希望第三列 SUM 结果本质上是 "totalVotes" 并包含这两个子查询的总和。然后我将 GROUP BY u.id ORDER BY totalVotes DESC LIMIT 3.

像这样:

  SELECT u.id, u.username, SUM(
                         (SELECT IFNULL(SUM(pv.type), 0) AS totalPostVotes
                          FROM posts_votes pv
                            JOIN posts p ON p.id = pv.post_id
                            JOIN users u ON u.id = p.user_id
                          GROUP BY u.id ORDER BY totalPostVotes DESC LIMIT 1)
                         +
                         (SELECT IFNULL(SUM(cv.type), 0) AS totalCommentVotes
                          FROM comments_votes cv                       
                            JOIN comments c ON c.id = cv.comment_id
                            JOIN users u ON u.id = c.user_id
                          GROUP BY u.id ORDER BY totalCommentVotes DESC LIMIT 1))
   AS totalVotes from users u
   GROUP BY u.id, u.username ORDER BY totalVotes DESC LIMIT 3

id | username | totalVotes
2   user2       11
1   user1       11
29  user29      11

发生的事情是 totalVotes 的结果确实是 "top" 用户的正确票数 11,但是这些用户中 none 是真正的顶级用户,正确的投票是以其他用户为幌子重复 3 次。我什至不确定此时用户是如何排序的,因为他们不是我认识的顺序。

当我添加 SELECT "u.id, u.username " IFNULL(SUM()) 时,子查询单独工作(它们给了我正确的用户)但是如果我 运行 整个块,我收到错误 "Operand should contain 1 column(s)" 所以我删除它们并恢复为仅 SELECT IFNULL(SUM())

我还注意到子查询只允许 LIMIT 1 个。那么我怎样才能获得前 3 个呢?我应该在某个地方做 UNION 还是“+”就足够了?这相当令人困惑。有人可以帮我吗?任何帮助表示赞赏。提前致谢!

更新代码,谢谢彼得:

     SELECT
     u.username,
     pv_sum.total AS postTotal,
     cv_sum.total AS commentTotal,
     IFNULL(pv_sum.total, 0) + IFNULL(cv_sum.total, 0) as totalVotes
     FROM users u
     LEFT JOIN (
          SELECT p.user_id, IFNULL(SUM(pv.type), 0) AS total
          FROM posts p
            JOIN posts_votes pv ON pv.post_id = p.id
          GROUP BY p.user_id
        ) pv_sum ON pv_sum.user_id = u.id
     LEFT JOIN (
          SELECT c.user_id, IFNULL(SUM(cv.type), 0) AS total
          FROM comments c
            JOIN comments_votes cv ON cv.comment_id = c.id
          GROUP BY c.user_id
        ) cv_sum ON cv_sum.user_id = u.id
     GROUP BY u.username, postTotal, commentTotal
     ORDER BY totalVotes DESC LIMIT 3;

不要将子查询放在 SELECT 部分,而是将它们加入用户 table:

SELECT 
    u.username, 
    pv_sum.total AS postTotal, 
    cv_sum.total as commentTotal, 
    IFNULL(pv_sum.total, 0) + IFNULL(cv_sum.total, 0) as totalVotes
FROM users u
LEFT JOIN (
   SELECT p.user_id, IFNULL(SUM(pv.type), 0) AS total
    FROM posts p 
    JOIN post_votes pv ON pv.post_id = p.id
    GROUP BY p.user_id
) pv_sum ON pv_sum.user_id = u.id
LEFT JOIN (
    SELECT c.user_id, IFNULL(SUM(cv.type), 0) AS total
    FROM comments c 
    JOIN comment_votes cv ON cv.comment_id = c.id
    GROUP BY c.user_id
) cv_sum ON cv_sum.user_id = u.id
GROUP BY u.id
ORDER BY totalVotes DESC
LIMIT 3;

Fiddle: http://sqlfiddle.com/#!9/980cb2/11