Ci sono molti modi per raggiungere questo obiettivo con le funzioni esistenti. Puoi utilizzare il funzioni della finestra first_value()
e last_value()
, combinato con DISTINCT
o DISTINCT ON
per ottenerlo senza join e subquery:
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);
Nota i frame per le funzioni della finestra !
Oppure puoi utilizzare le funzioni di aggregazione di base in una sottoquery e 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;
Assumendo (userid, rank)
univoco o le tue esigenze sarebbero ambigue.
Shichinin nessun samurai
Per richiesta nei commenti, lo stesso solo per le ultime sette righe per userid (o quanti se ne possono trovare, se sono di meno):
Ancora una volta, uno dei tanti modi possibili. Ma credo che questo sia uno dei più brevi:
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;
Notare l'ordinamento invertito. La prima riga è la voce "più recente". Mi occupo di un frame di (max.) 7 righe e scelgo solo i risultati per la voce più recente con DISTINCT ON
.