为什么评论错误?

时间:2014-06-28 20:32:58

标签: mysql

我需要为项目计算评论和投票,但评论错误。

   SELECT projects . * , COUNT( votes.project_id ) AS votes, COUNT( comments.user_id) AS comments
    FROM  `projects` 
    LEFT JOIN  `votes` ON  `projects`.`id` =  `votes`.`project_id` 
    LEFT JOIN  `comments` ON  `projects`.`id` =  `comments`.`project_id` 
    WHERE  `votes`.`created_at` >  '2014-05-31 20:21:43' AND 
    GROUP BY  `projects`.`id` 
    ORDER BY  `votes` DESC 

http://i.imgur.com/CcRo5JC.png

enter image description here

输出:

http://i.imgur.com/aCUZETO.png

2 个答案:

答案 0 :(得分:2)

你需要计算不同的值,所以有点像:

SELECT projects . * , COUNT( DISTINCT votes.user_id ) AS votes, COUNT( DISTINCT comments.user_id) AS comments
FROM  `projects` 
LEFT JOIN  `votes` ON  `projects`.`id` =  `votes`.`project_id` 
LEFT JOIN  `comments` ON  `projects`.`id` =  `comments`.`project_id` 
WHERE  `votes`.`created_at` >  '2014-05-31 20:21:43' AND 
GROUP BY  `projects`.`id` 
ORDER BY  `votes` DESC 

答案 1 :(得分:1)

计数错误"因为COUNT()聚合计算结果集中的行,而不是来自各个表的行。如果project_id = 1表中有两行comments,则两个计数聚合都将返回8.

基本上,comments中的每一行都与projects中的每一行匹配。

有几种方法可以解决这个问题。一种是在SELECT列表中使用子选择,尽管对于大型集合来说这可能是昂贵的(在性能方面):

SELECT p.*
     , ( SELECT COUNT(1)
           FROM votes v
          WHERE v.project_id = p.project_id
            AND v.created_at > '2014-05-31 20:21:43'
       ) AS votes
     , ( SELECT COUNT(1)
           FROM comments c
          WHERE c.project_id = p.project_id
       ) AS comment_cnt
  FROM projects p
HAVING votes > 0
 ORDER BY votes DESC

(包含HAVING子句以模拟原始查询;在原始中,LEFT JOIN到投票表的"外部性"被votes.created_at中的谓词否定b WHERE子句。)


另一种方法是分别从每个表中获取计数(通过project_id在两个单独的查询中获取计数,引用为内联视图,然后将这些计数与JOIN操作结合起来。例如:

SELECT p.*
     , w.votes
     , IFNULL(d.comment_cnt,0) AS comment_cnt
  FROM projects p
  JOIN ( SELECT v.project_id
              , COUNT(1) AS votes
           FROM votes v
          WHERE v.created_at > '2014-05-31 20:21:43'
          GROUP BY v.project_id
       ) w
    ON w.project_id = p.project_id
  LEFT
  JOIN ( SELECT c.project_id
               , COUNT(1) AS comment_cnt
           FROM comments c
          GROUP BY c.project_id
       ) d
    ON d.project_id = p.project_id
 ORDER BY w.votes DESC

(因为规范只返回有"投票"大于零的行,我们可以使用INNER JOIN排除没有任何"投票& #34;。对于注释计数,我们使用OUTER JOIN,并简单地用零替换任何NULL值。

还有其他方法。

性能取决于行数,引用列的基数,可用索引,优化器选择的执行计划等。