Има много начини да постигнете това със съществуващите функции. Можете да използвате съществуващия прозоречни функции 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)
, или вашите изисквания биха били двусмислени.
Шичинин не самурай
По искане в коментарите, същото само за последните седем реда на потребителско име (или колкото можете да намерите, ако са по-малко):
Отново един от многото възможни начини. Но смятам, че това е един от най-кратките:
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
.