Перевод запросов из MySQL в PostgreSQL: GROUP BY

Здравствуйте!
Перевожу базу на postgresql.
Есть такой запрос для MySQL:
SELECT t.id, t.name, t.size, MIN(p.to_go) AS to_go, COUNT(p.id) as count
FROM torrents t, peers p
WHERE
t.multitracker_on = 1
AND p.torrent = t.id
AND t.ban = 0
AND to_go > 0
GROUP BY p.torrent
ORDER BY added DESC
LIMIT 10
При его выполнении на postgresql выдаёт ошибку: ERROR: колонка "t.id" должна фигурировать в выражении GROUP BY или использоваться в агрегатной функции
Добавил MIN(t.id) вместо t.id, возникает та же ошибка, только для другого поля.
В конце концов возникает ошибка: ERROR: колонка "t.added" должна фигурировать в выражении GROUP BY или использоваться в агрегатной функции
И даже добавление MIN(t.added) выдаёт туже ошибку.
Что делать?

Опции просмотра комментариев

Выберите предпочитаемый вами способ показа комментариев и нажмите "Сохранить настройки" для активации изменений.

Почитать мануал и понять что

Почитать мануал и понять что такое GROUP BY и как работают агрегатные функции.

Вы группируете по полю p.torrent, но каковы условия группировки? Условия подразумевают исполнение агрегатной функции НАД ВСЕМИ полями таблицы, которые у вас в SELECT. А у вас в запросе только над одним полем. Поэтому СУБД не знает что делать с остальными полями - вычислять MIN или AVG или ещё чего?

Вы бы лучше показали бы структуру таблицы, кусок данных и что хотите получить. Тогда было бы проще разговаривать.

Хм, понятно, в SELECT у

Хм, понятно, в SELECT у полей, которые не используют агрегатные функции, должны быть одинаковые.
Вот примерные данные таблицы
torrents
id | name | size | multitracker_on | ban
1 | Первый торрент | 111 | true | false
2 | Второй торрент | 222 | true | false

peers
id | torrent | to_go
1 | 1 | 0
2 | 1 | 25
3 | 1 | 100
4 | 2 | 1000
5 | 2 | 5

Мне нужно получить
1 | Первый торрент | 111 | 25 | 3
2 | Второй торрент | 222 | 5 | 2

Ну и? В чём

Ну и? В чём проблема-то?

SELECT t.id, t.name, size, min(to_go), count(p.id) 
FROM torrents t 
INNER JOIN peers p ON p.torrent=t.id 
GROUP BY t.id, t.name, t.size 
ORDER BY t.name;

id |                   name                   | size | min | count 
----+------------------------------------------+------+-----+-------
  2 | Второй торрент                           |  222 |   5 |     2
  1 | Первый торрент                           |  111 |   0 |     3
(2 rows)

Большое спасибо! Т.е. надо

Большое спасибо!
Т.е. надо указывать все поля, с которыми не проводятся агрегатные функции в GROUP BY?

Попробуйте понять простой

Попробуйте понять простой принцип. Вы выбираете список полей из некой виртуальной таблицы, которая получена на этапе соединения таблиц. При этом те записи, поля которых вы укажете в группировке GROUP BY как бы схлопываются по одинаковым значениям этих полей. Если вы хотите в SELECT задать поля, которых нет в GROUP BY, то получается, что у вас должно появиться куча записей с одинаковыми значениями полей.

Непонятно? Тогда рекомендую взять тот же запрос, что я вам написал, но убрав оттуда агрегаты и GROUP BY. Вот запрос:

SELECT t.id, t.name, size 
FROM torrents t 
INNER JOIN peers p ON p.torrent=t.id 
ORDER BY t.name;

А вот результат:

 id |                   name                   | size 
----+------------------------------------------+------
  2 | Второй торрент                           |  222
  2 | Второй торрент                           |  222
  1 | Первый торрент                           |  111
  1 | Первый торрент                           |  111
  1 | Первый торрент                           |  111
(5 rows)

Видите? Как я и писал - куча записей с одинаковыми значениями. GROUP BY в данном случае схлапывает лишние записи до одной, при этом производится вычисление агрегатных функций по полям to_go и id.

Всё понятно стало, спасибо

Всё понятно стало, спасибо огромное!
После в MySQL немного по-другому.
И опять же, большое спасибо за разжёвывание и вообще за очень полезный сайт!

Опции просмотра комментариев

Выберите предпочитаемый вами способ показа комментариев и нажмите "Сохранить настройки" для активации изменений.

Back to top

(С) Виктор Вислобоков, 2008-2023