Подсчет количества положительных и отрицательных голосов:

У меня есть следующие таблицы:

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

Значение — это tiny_int, которое может быть равно 1 или -1.

Я хочу подсчитать количество положительных и отрицательных голосов для каждого сообщения:

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

Почему следующий код не работает?

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"));
});

Я также пробовал следующее, это приводит к тому, что все голоса будут одинаковыми для каждого сообщения:

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"));
}

Также есть ли способ сделать это без необходимости многократно запрашивать базу данных для каждого сообщения? Как что-то, что постоянно меняется [вот так], может быть (mem) кэшировано?


person jonnnnnnnnnie    schedule 20.04.2011    source источник
comment
Что возвращает sql_select? Есть ли документация по этой функции?   -  person webbiedave    schedule 21.04.2011
comment
В вашем текущем SQL вы используете SUM, хотя на самом деле вы могли бы использовать COUNT, что дало бы более быстрые результаты.   -  person Andre Backlund    schedule 21.04.2011
comment
sql_select - это функция, которую я сделал сам. Она выдает исключение, если запрос sql неверен (т.е. не может выполнить выбор)   -  person jonnnnnnnnnie    schedule 21.04.2011


Ответы (2)


Вы можете сделать свой подсчет в одном запросе:

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 = ...

Если вы хотите получить положительные и отрицательные голоса за пост:

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

Если вы хотите объединить свой первый запрос и второй запрос, вы можете получить:

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
person Thomas    schedule 20.04.2011
comment
Как бы вы совместили это с первым запросом? Таким образом, я могу выбрать все сообщения и голоса, связанные с каждым сообщением. - person jonnnnnnnnnie; 21.04.2011
comment
@jonnnnnnnnnie - Вы бы просто вставили этот запрос в производную таблицу. Я расширил свой ответ, чтобы проиллюстрировать. - person Thomas; 21.04.2011

Я не могу найти функцию sql_select(), которую вы используете, но, возможно, вам лучше использовать count(*) в вашем SQL вместо того, чтобы пытаться sum(). Вам просто нужно подсчитать строки, как это выглядит, а не суммировать значения. Вы также можете немного пофантазировать и использовать GROUP BY:

SELECT value, count(value) AS value_count FROM author_vote WHERE post_id = $id GROUP BY value

Это вернет одну строку для каждого уникального значения. Каждая возвращенная строка будет содержать уникальное значение и количество строк, использующих это значение.

person penguin359    schedule 20.04.2011