Вы не , фактически используете агрегатные функции. Вы используете оконные функции . Вот почему PostgreSQL требует, чтобы sp.payout
и s.buyin
были включены в предложение GROUP BY
.
При добавлении предложения OVER
агрегатная функция sum()
превращается в оконную функцию, которая агрегирует значения для каждого раздела, в то время как сохраняет все строки.
Вы можете комбинировать оконные функции и агрегатные функции . Агрегации применяются в первую очередь. Я не понял из вашего описания, как вы хотите обрабатывать несколько выплат / покупок за событие. Как предположение, я рассчитываю их сумму за событие. Теперь Я могу удалить sp.payout
и s.buyin
из предложения GROUP BY
и получить по одной строке на player
и event
:
SELECT p.name
, e.event_id
, e.date
, sum(sum(sp.payout)) OVER w
- sum(sum(s.buyin )) OVER w AS "Profit/Loss"
FROM player p
JOIN result r ON r.player_id = p.player_id
JOIN game g ON g.game_id = r.game_id
JOIN event e ON e.event_id = g.event_id
JOIN structure s ON s.structure_id = g.structure_id
JOIN structure_payout sp ON sp.structure_id = g.structure_id
AND sp.position = r.position
WHERE p.player_id = 17
GROUP BY e.event_id
WINDOW w AS (ORDER BY e.date, e.event_id)
ORDER BY e.date, e.event_id;
В этом выражении: sum(sum(sp.payout)) OVER w
, внешний sum()
является оконной функцией, внутренний sum()
является агрегатной функцией.
Предполагая, что p.player_id
и e.event_id
равны PRIMARY KEY
в соответствующих таблицах.
Я добавил e.event_id
к ORDER BY
предложения WINDOW
, чтобы получить детерминированный порядок сортировки. (В одну и ту же дату может быть несколько событий.) Также включен event_id
в результат, чтобы различать несколько событий в день.
Хотя запрос ограничивается одиночным игроком (WHERE p.player_id = 17
), нам не нужно добавлять p.name
или p.player_id
к GROUP BY
и ORDER BY
. Если одно из объединений будет чрезмерно умножать строки, полученная сумма будет неправильной (частично или полностью умножена). Группировка по p.name
не смогла восстановить запрос.
Я также удалил e.date
из предложения GROUP BY
. Первичный ключ e.event_id
охватывает все столбцы входной строки , начиная с PostgreSQL 9.1 .
Если изменить запрос, чтобы вернуть сразу нескольких игроков, адаптируйте:
...
WHERE p.player_id < 17 -- example - multiple players
GROUP BY p.name, p.player_id, e.date, e.event_id -- e.date and p.name redundant
WINDOW w AS (ORDER BY p.name, p.player_id, e.date, e.event_id)
ORDER BY p.name, p.player_id, e.date, e.event_id;
Если p.name
не определено уникально (?), Группа и порядок player_id
дополнительно для получения правильных результатов в детерминированном порядке сортировки.
Я сохранил только e.date
и p.name
в GROUP BY
, чтобы иметь одинаковый порядок сортировки во всех пунктах, надеясь на выигрыш в производительности. Иначе, вы можете удалить столбцы там. (Аналогично только для e.date
в первом запросе.)