#sql #postgresql
Вопрос:
Там есть столик:
create table transfers(
ts timestamp without time zone,
departure varchar(3),
destination varchar(3),
price numeric
);
содержащий:
ts departure destination price
______________________________________________________
2020-11-01T15:00:00Z Chicago Berlin 500
2020-11-01T12:00:05Z Chicago Berlin 400
2020-11-01T20:01:00Z Chicago Berlin 920
2020-11-01T20:01:00Z London Berlin 800
2020-11-01T22:00:00Z London Berlin 750
Мне нужно получить цены для каждого пункта отправления с самой высокой отметкой времени, поэтому результат должен быть:
ts departure destination price
______________________________________________________
2020-11-01T20:01:00Z Chicago Berlin 920
2020-11-01T22:00:00Z London Berlin 750
Я сделал это с помощью запроса:
with max_ts_per_departure AS (
SELECT MAX(ts) AS ts, departure
FROM transfers
GROUP BY departure
)
SELECT t.ts, mtpd.departure, t.price
FROM max_ts_per_departure AS mtpd
INNER JOIN transfers AS t
ON mtpd.departure=t.departure AND mtpd.ts=t.ts;
Есть ли способ сократить запрос и избежать использования оператора WITH, не слишком замедляя время выполнения? Реальные данные намного больше.
Ответ №1:
Попробуйте использовать DISTINCT ON
:
SELECT DISTINCT ON (departure) *
FROM transfers
ORDER BY departure, ts DESC;
Комментарии:
1. Это возвращает: «цена вылета max_ts Чикаго 400 2020-11-01T12:00:05Z Чикаго 500 2020-11-01T15:00:00Z Чикаго 920 2020-11-01T20:01:00Z Лондон 750 2020-11-01T22:00:00Z Лондон 800 2020-11-01T20:01:00Z» Не ожидаемый результат.
2. Попробуйте обновленный ответ.
3. Это работает. Для полной бд время выполнения становится медленным, но я решил эту проблему с помощью дополнительного индекса.
CREATE INDEX idx_max_ts ON transfers (ts DESC NULLS LAST, departure);
Спасибо.