Group by в сложном запросе

Exact
Дата: 26.03.2015 10:41:57
У меня есть две таблицы. Игроки (упрощенный вариант): players(id, team_id) и игры games(id, date, home_team_id, away_team_id).

Мне нужно вывести id будущих игр для каждого игрока. В теории все понятно, нужно объединить две таблицы (через games.home_team_id = players.team_id or games.away_team_id = players.team_id). Затем сгруппировать по игроку, отфильтровать прошедшие игры и выбрать среди них минимальные даты). Но на практике не удается создать корректный запрос, который бы работал...

SELECT min(games.date) AS min_1, players.id AS u_id
FROM games join players on games.home_team_id=players.team_id or games.away_team_id=players.team_id where games.date > '2015-03-26 12:36:00+000' GROUP BY players.id ORDER BY players.id


Вот такой запрос работает, и на первый взгляд выдает корректные данные, но если я попытаюсь добавить в SELECT games.id, субд сообщит мне следующее: column "games.id" must appear in the GROUP BY clause or be used in an aggregate function
А если я пойду у нее на поводу и добавлю в GROUP BY games.id, то минимальная дата для каждой отдельно взятой игры будет, что логично - датой этой игры. Т.е. я получу не по одной игре для каждого игрока, а все его игры, что не выполняет поставленную задачу.

Как выйти из этой ситуации? Долго уже бьюсь, но решения найти не удается..
Exact
Дата: 26.03.2015 10:56:09
Exact, удалось найти на форуме решение, выводить в select агрегатную функцию, типа max(). Если данные одинаковые (а так и есть для одной и той же игры), то все будет ок. Но выглядит немного.. костыльно что ли
Exact
Дата: 26.03.2015 11:07:48
автор
удалось найти на форуме решение, выводить в select агрегатную функцию, типа max(). Если данные одинаковые (а так и есть для одной и той же игры), то все будет ок.

Как оказалось, это не соответствует действительности. MIN (games.id) никак не связана с min (games.sheduled)
Maxim Boguk
Дата: 26.03.2015 13:15:20
Exact
У меня есть две таблицы. Игроки (упрощенный вариант): players(id, team_id) и игры games(id, date, home_team_id, away_team_id).

Мне нужно вывести id будущих игр для каждого игрока. В теории все понятно, нужно объединить две таблицы (через games.home_team_id = players.team_id or games.away_team_id = players.team_id). Затем сгруппировать по игроку, отфильтровать прошедшие игры и выбрать среди них минимальные даты). Но на практике не удается создать корректный запрос, который бы работал...

SELECT min(games.date) AS min_1, players.id AS u_id
FROM games join players on games.home_team_id=players.team_id or games.away_team_id=players.team_id where games.date > '2015-03-26 12:36:00+000' GROUP BY players.id ORDER BY players.id


Вот такой запрос работает, и на первый взгляд выдает корректные данные, но если я попытаюсь добавить в SELECT games.id, субд сообщит мне следующее: column "games.id" must appear in the GROUP BY clause or be used in an aggregate function
А если я пойду у нее на поводу и добавлю в GROUP BY games.id, то минимальная дата для каждой отдельно взятой игры будет, что логично - датой этой игры. Т.е. я получу не по одной игре для каждого игрока, а все его игры, что не выполняет поставленную задачу.

Как выйти из этой ситуации? Долго уже бьюсь, но решения найти не удается..


читайте документацию по DISTINCT ON
это то что вам надо для решения этой задачи

--Maxim Boguk
www.postgresql-consulting.ru
лопата
Дата: 26.03.2015 14:35:14
Maxim Boguk,
таки лучше послать сразу к LATERAL , хотя и ограничено >~ 9.3, но идеологически верно (до тех пор, пока оптимайзер ПЖ не научится таки прилично считать DISTINCT ON) . А иначе такие гробы из под школоты, освоившей DISTINCT ON лезут, мать моя -- женщина.
Ivan Durak
Дата: 26.03.2015 15:29:47
какие еще дистинкт оны?

select * from
(
  SELECT games.date, players.id, games.id,  row_number() over (partition by players.id order by games.date) as SORT
  FROM games 
  inner join players on games.home_team_id=players.team_id or games.away_team_id=players.team_id 
  where games.date > '2015-03-26 12:36:00+000' 
) sub
where SORT = 1;
лопата
Дата: 26.03.2015 17:03:00
Ivan Durak,
дурак ты, ваня

lateral вдоль индекса с LIMIT 1 дешевле окна . много дешевле. часто -- на порядки. а distinct on ... order by -- скорее всего сравним (в нынешней реализации оптимайзера) с окном.