SQL Group By и Order By с агрегатными функциями - PullRequest
0 голосов
/ 15 марта 2012

Я собираю приложение на Rails и столкнулся с проблемой SQL. Хотя это можно решить в Sqlite3, когда я перемещаю его на свой сервер Heroku, на котором работает Postgres, он задыхается и умирает. Ситуация выглядит следующим образом:

SPORTS
-----------------------------
|   id    |      title      |
-----------------------------
|   1     |  Baseball       |
-----------------------------

SPORTS_VOTE
------------------------------------
|  id  |   sport_id    |    vote   |
------------------------------------
|  1   |       1       |     1     |
------------------------------------

Столбец голосования может быть либо 1, либо -1. Я хотел бы получить список видов спорта, упорядоченных по сумме голосов. Запрос, который я использовал в Sqlite3, был примерно таким:

  SELECT s.title, sum(sv.vote)
    FROM sports s 
   INNER JOIN sports_vote sv ON s.id = sv.sport_id 
 GROUP BY s.id
 ORDER BY sum(sv.vote);

В любой респектабельной БД этот запрос жалуется на агрегатные функции и т. Д. Каков наилучший способ сделать это? Мне лучше оставить поле «голосование» в таблице «Спорт» и обновлять его, когда поданы голоса? В таблицу Sports_Vote также записывается идентификатор пользователя, отправившего голосование, поэтому он необходим.

Во-вторых, я хотел бы идеально объединить две одинаковые таблицы, чтобы я получил хороший список, скажем, Sports & Cookies в порядке убывания голосов (Хоккей занял первое место, Maple Cookies № 2, Football # 3 и т. Д. ). Любой совет?

1 Ответ

4 голосов
/ 15 марта 2012

Практическое правило для предотвращения ошибок при использовании group by:

  • Все неагрегированные столбцы должны быть включены в предложение group by.

Следовательно, ваш запрос должен быть:

 SELECT s.id, s.title, sum(sv.vote)
    FROM sports s 
   INNER JOIN sports_vote sv ON s.id = sv.sport_id 
 GROUP BY s.id, s.title
 ORDER BY sum(sv.vote);

OR

 SELECT s.title, sum(sv.vote)
    FROM sports s 
   INNER JOIN sports_vote sv ON s.id = sv.sport_id 
 GROUP BY s.title
 ORDER BY sum(sv.vote);

Для объединения со второй таблицей и рангом вы можете просто использовать union (order by будет применяться к комбинированному результату):

 SELECT s.title, sum(sv.vote) vote_count
    FROM sports s 
   INNER JOIN sports_vote sv ON s.id = sv.sport_id 
 GROUP BY s.title
 UNION   
 SELECT s.title, sum(sv.vote) vote_count
    FROM cookies s 
   INNER JOIN cookies_vote sv ON s.id = sv.sport_id 
 GROUP BY s.title
 ORDER BY vote_count DESC;

Относительно вашего вопроса о том, следует ли вести подсчет голосов в спортивной таблице и обновлять информацию при каждом голосовании, это зависит. Это даст вам лучшую производительность при генерации отчетов, подобных приведенным выше (поскольку group by и inner join больше не понадобятся), но это снизит производительность подачи голосов (поскольку теперь вам нужно вставить И обновить вторую таблицу). Так что это зависит от ваших приоритетов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...