GROUP BY с МАКС. (ДАТА) [дубликаты]

97

Я пытаюсь перечислить последний пункт назначения (время отправления MAX) для каждого поезда в таблице, например:

Train    Dest      Time
1        HK        10:00
1        SH        12:00
1        SZ        14:00
2        HK        13:00
2        SH        09:00
2        SZ        07:00

Желаемый результат должен быть:

Train    Dest      Time
1        SZ        14:00
2        HK        13:00

Я пробовал использовать

SELECT Train, Dest, MAX(Time)
FROM TrainTable
GROUP BY Train

я получил ошибку ora-00979, а не выражение GROUP BY, заявив, что я должен включить 'Dest' в свою группу по инструкции. Но, конечно, это не то, что я хочу...

Можно ли это сделать в одной строке SQL?

  • 2
    Для тех, кто задается вопросом, самое чистое решение "plain sql" - решение Джо . Второй приз достается Клаудио .
Теги:
group-by
greatest-n-per-group
ora-00979

6 ответов

107
Лучший ответ

Вы не можете включить неагрегированные столбцы в свой результирующий набор, которые не сгруппированы. Если поезд имеет только одно место назначения, просто добавьте столбец назначения в предложение group by, иначе вам нужно пересмотреть ваш запрос.

Try:

SELECT t.Train, t.Dest, r.MaxTime
FROM (
      SELECT Train, MAX(Time) as MaxTime
      FROM TrainTable
      GROUP BY Train
) r
INNER JOIN TrainTable t
ON t.Train = r.Train AND t.Time = r.MaxTime
  • 10
    Осторожно, это не будет работать, если есть «связи» для максимального (времени), потому что вы будете получать несколько строк. Вам нужно добавить group by train,dest сразу за весь запрос выше.
  • 0
    Хорошо. Но как это работает, если внутренний запрос объединен с другой таблицей? Давайте представим, что у Destination в TrainTable есть собственная таблица. Таким образом, внутренний запрос будет выглядеть так: выберите t.train, d.dest, max (time) из TrainTable t присоединитесь к пункту назначения d в группе t.destid = d.id по t.train, d.dest
106
SELECT train, dest, time FROM ( 
  SELECT train, dest, time, 
    RANK() OVER (PARTITION BY train ORDER BY time DESC) dest_rank
    FROM traintable
  ) where dest_rank = 1
  • 0
    Thx Thilo :-) Действительно, ваш ответ также правильный. Но так как я могу принять только 1 ответ, я выбрал Оливера, потому что сначала попробовал его ответ.
  • 6
    @ Овен - ответ Тило превосходит ответ Оливера, поскольку ответ Тило будет выполнять меньше операций ввода-вывода. Аналитическая функция позволяет SQL обрабатывать таблицу за один проход, тогда как решение Оливера требует нескольких проходов.
Показать ещё 8 комментариев
55

Вот пример, который использует только левое соединение, и я считаю, что он эффективнее любой группы по методу: Блог ExchangeCore

SELECT t1.*
FROM TrainTable t1 LEFT JOIN TrainTable t2
ON (t1.Train = t2.Train AND t1.Time < t2.Time)
WHERE t2.Time IS NULL;
  • 7
    Мне нравится этот подход, потому что он использует только стандартный SQL и работает очень хорошо и быстро.
  • 2
    это лучший оптимизированный ответ
Показать ещё 8 комментариев
8

Другое решение:

select * from traintable
where (train, time) in (select train, max(time) from traintable group by train);
  • 1
    Осторожно, это не будет работать, если есть «связи» для максимального (времени), потому что вы будете получать несколько строк. Используйте это вместо этого: select * from traintable where (train, time) in (select train, max(time) from traintable group by train) group by train,dest;
8

Пока нет дубликатов (и поезда, как правило, поступают только на одну станцию ​​за раз)...

select Train, MAX(Time),
      max(Dest) keep (DENSE_RANK LAST ORDER BY Time) max_keep
from TrainTable
GROUP BY Train;
  • 1
    "и поезда, как правило, прибывают только на одну станцию за один раз" ... Это не указано.
3

Я знаю, что опаздываю на вечеринку, но попробуйте это...

SELECT 
    `Train`, 
    `Dest`,
    SUBSTRING_INDEX(GROUP_CONCAT(`Time` ORDER BY `Time` DESC), ",", 1) AS `Time`
FROM TrainTable
GROUP BY Train;

Src: Групповая документация сторон

Изменить: исправлен синтаксис sql

Ещё вопросы

Сообщество Overcoder
Наверх
Меню