Search code examples
phpmysqlvoting

Counting number of positive and negative votes:


I have the following tables:

post (id, title, content) etc
author (id, username) etc
author_vote (post_id, author_id, value)

Value is a tiny_int that can either be 1 or -1.

I want to count the number of positive and negative votes for each post:

$posts = sql_select($link, "SELECT post.*, author.username 
                            FROM post, author 
                            AND author.id = post.author_id");

Why does the following code not work?

array_walk($posts, function(&$post, $link){
   $post['positive'] = sql_select($link, "SELECT SUM(value) FROM author_vote WHERE post_id = $post['id']
                                            AND value  = 1");

   $post['negative'] = abs(sql_select($link, "SELECT SUM(value) FROM author_vote WHERE post_id = $post['id']
                                            AND value  = -1"));
});

I've also tried the following, this causes all the votes to be the same for each post:

foreach ($posts as &$post)
{
   $id = $post['id'];
   $post['positive'] = (int)sql_select($link, "SELECT SUM(value) FROM author_vote WHERE post_id = $id
                                           AND value  = 1");
   $post['negative'] = (int)abs(sql_select($link, "SELECT SUM(value) FROM author_vote WHERE post_id = $id
                                               AND value  = -1"));
}

Also is there any way to do this without having to query the database multiple times for each post? How would something that is constantly changing [like this] be (mem)cached?


Solution

  • You could do your count in a single query:

    Select Sum( Case When value < 0 Then 1 Else 0 End ) As NegVotes
        , Sum( Case When value > 0 Then 1 Else 0 End ) As PosVotes
    From author_vote
    Where post_id = ...
    

    If you want the positive and negative votes per post:

    Select post_id
        , Sum( Case When value < 0 Then 1 Else 0 End ) As NegVotes
        , Sum( Case When value > 0 Then 1 Else 0 End ) As PosVotes
    From author_vote
    Group By post_id
    

    If you wanted to combine your first query and second query you can get:

    Select post....
        , author.username 
        , Coalesce(post_count.NegVotes,0) As NegVotes
        , Coalesce(post_count.PosVotes,0) As PosVotes
    From post
        Join author
            On author.id = post.author_id
        Left Join   (
                    Select post_id
                        , Sum( Case When value < 0 Then 1 Else 0 End ) As NegVotes
                        , Sum( Case When value > 0 Then 1 Else 0 End ) As PosVotes
                    From author_vote
                    Group By post_id
                    ) As post_count
            On post_count.post_id = post.post_id