如何选择评论计数,投票总数以及活跃用户是否已投票

时间:2016-11-13 19:20:36

标签: mysql count sum left-join

我无法构建MySQL查询以返回准确的评论计数,投票总数和活跃用户投票。

我的桌子是

wall_posts ( id, message, username, etc )
comments   ( id, wall_id, username, text, etc )
votes      ( id, wall_id, vote (+1 or -1), username )

我的查询看起来像这样

SELECT
    wall_posts.*,
    COUNT( comments.wall_id ) AS comment_count,
    COALESCE( SUM( v1.vote ), 0 ) AS vote_tally,
    v2.vote 
FROM
    wall_posts 
    LEFT JOIN comments ON wall_posts.id = comments.wall_id 
    LEFT JOIN votes v1 ON wall_posts.id = v1.wall_id 
    LEFT JOIN votes v2 ON wall_posts.id = v2.wall_id AND v2.username=:username 
WHERE
    symbol =: symbol
GROUP BY
    wall_posts.id
ORDER BY
    date DESC
LIMIT 15

它始终为特定活动用户投票(+1或-1)返回正确的值,如果没有投票则为null。如果对某个项目没有评论,则总投票金额是正确的。如果有任何评论,则投票金额将始终等于评论计数,如果投票数减少,则可能带有负号,但总是等于评论数量。

我认为它显然是我连接我的桌​​子的方式,但我不知道为什么它复制评论计数,1000000点给可以向我解释的人:)

1 个答案:

答案 0 :(得分:0)

您需要在子查询中执行聚合操作。现在,您将JOIN所有表格(预聚合)放在一起。如果您删除聚合(以及GROUP BY),您将看到大量数据,这些数据实际上并不重要。

相反,试试这个(注意我使用的是VIEW):

CREATE VIEW walls_posts_stats AS

SELECT
    wall_posts.id,
    COALESCE( comments_stats.comment_count, 0 ) AS comment_count,
    COALESCE( votes_stats.vote_tally, 0 ) AS vote_tally
FROM

    wall_posts

    LEFT OUTER JOIN
    (
        SELECT
            wall_id,
            COUNT(*) AS comment_count
        FROM
            comments
        GROUP BY
            wall_id
    ) AS comments_stats ON wall_posts.id = comments_stats.wall_id

    LEFT OUTER JOIN
    (
        SELECT
            wall_id,
            SUM( vote ) AS vote_tally
        FROM
            votes
        GROUP BY
            wall_id
    ) AS votes_stats ON wall_posts.id = votes_stats.wall_id

然后您可以使用原始墙数据查询它:

SELECT
    wall_posts.*, -- note: avoid the use of * in production queries
    stats.comment_count,
    stats.vote_tally,
    user_votes.vote
FROM
    wall_posts
    INNER JOIN walls_posts_stats AS stats ON wall_posts.id = stats.id
    LEFT OUTER JOIN
    (
        SELECT
            wall_id,
            vote
        FROM
            votes
        WHERE
            username = :username
    ) AS user_votes ON wall_posts.id = user_votes.wall_id
ORDER BY
    date DESC
LIMIT 15

假设您可以将它组合成一个大型查询(基本上将VIEW主体复制+粘贴到INNER JOIN walls_posts_stats子句中)但我觉得这会引入可维护性问题。

虽然MySQL确实支持视图,但它不支持参数化视图(也就是可组合的表值函数;存储过程不可组合),这就是为什么user_votes子查询不在walls_posts_stats视图中