我需要为项目计算评论和投票,但评论错误。
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
输出:
答案 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值。
还有其他方法。
性能取决于行数,引用列的基数,可用索引,优化器选择的执行计划等。