2010-08-16 2 views
102

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

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 

от I получил "ORA-00979 не является групповым выражением" ошибка о том, что Я должен указать «Dest» в моей группе по инструкции. Но, конечно, это не то, что я хочу ...

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

+2

Для тех, которые задаются вопросом, самое чистое «простое sql» решение - [Джо] (http://stackoverflow.com/a/14841015/632951). Второй приз принадлежит [Claudio] (http://stackoverflow.com/a/24370489/632951). – Pacerier

ответ

109

Вы не можете включать неагрегатные столбцы в свой набор результатов, которые не сгруппированы. Если поезд имеет только один пункт назначения, то просто добавьте столбец назначения в предложение 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 
+7

Осторожно , это не будет работать, если есть «привязки» для max (time), потому что вы будете получать несколько строк. Вам нужно добавить 'group by train, dest' прямо за весь запрос выше. – Pacerier

118
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 ответ, я выбрал Оливера, потому что сначала попробовал его ответ. – Aries

+5

@Aries. Ответ Тило превосходит Оливера, так как ответ Тило будет иметь тенденцию выполнять меньше ввода-вывода. Аналитическая функция позволяет SQL обрабатывать таблицу за один проход, тогда как решение Оливера требует нескольких проходов. –

+3

да, я согласен. Этот ответ должен быть «правильным». – Russell

8

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

select Train, MAX(Time), 
     max(Dest) keep (DENSE_RANK LAST ORDER BY Time) max_keep 
from TrainTable 
GROUP BY Train; 
+1

"и поезда имеют тенденцию поступать только на одну станцию ​​за раз" ... Это не указано. – Pacerier

61

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

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 и работает очень хорошо и быстро. – GreenTurtle

+2

это лучший оптимизированный ответ – diEcho

+0

Замечательное решение. На мой взгляд, гораздо лучше, чем сложная группа по статьям. Я просто обожаю ловко элегантные вещи, как это, спасибо! –

8

Аноф эр решение:

select * from traintable 
where (train, time) in (select train, max(time) from traintable group by train); 
+1

Осторожно, это не сработает, если есть «привязки» для max (time), потому что вы будете получать несколько строк. Используйте это вместо: 'select * from traintable где (поезд, время) в (выберите поезд, max (время) из группы, на которую можно отправиться на поезде) группа на поезде, dest; ' – Pacerier

3

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

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

Src: Group Concat Documentation

Edit: фиксированный SQL синтаксис

 Смежные вопросы

  • Нет связанных вопросов^_^