Ответ 1
ранг самой новой записи (по метке времени) - ранг самой старой записи (по метке времени)
Существует много способов добиться этого с помощью существующих функций.
Вы можете использовать существующие функции окна first_value()
и last_value()
в сочетании с DISTINCT
или DISTINCT ON
, чтобы получить его без соединений и подзапросов
SELECT DISTINCT ON (userid)
userid
, last_value(rank) OVER w
- first_value(rank) OVER w AS rank_delta
FROM rankings
WINDOW w AS (PARTITION BY userid ORDER BY ts
ROWS BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING);
Обратите внимание на пользовательские фреймы для функций окна!
Или вы можете использовать основные агрегированные функции в подзапросе и JOIN:
SELECT userid, r2.rank - r1.rank AS rank_delta
FROM (
SELECT userid
, min(ts) AS first_ts
, max(ts) AS last_ts
FROM rankings
GROUP BY 1
) sub
JOIN rankings r1 USING (userid)
JOIN rankings r2 USING (userid)
WHERE r1.ts = first_ts
AND r2.ts = last_ts;
Предполагая уникальный (userid, rank)
, или ваши требования будут неоднозначными.
Шичинин без самураев
... a.k.a. "7 Самурай"
По запросу в комментариях то же самое только для последних семи строк для userid (или столько, сколько их можно найти, если их меньше):
Опять один из многих возможных способов. Но я считаю, что это один из самых коротких:
SELECT DISTINCT ON (userid)
userid
, first_value(rank) OVER w
- last_value(rank) OVER w AS rank_delta
FROM rankings
WINDOW w AS (PARTITION BY userid ORDER BY ts DESC
ROWS BETWEEN CURRENT ROW AND 7 FOLLOWING)
ORDER BY userid, ts DESC;
Обратите внимание на отмененный порядок сортировки. Первая строка - это "новейшая" запись. Я охватываю рамку (максимум) 7 строк и выбираю только результаты для самой новой записи с DISTINCT ON
.