Det finns många sätt att uppnå detta med befintliga funktioner. Du kan använda den befintliga fönsterfunktioner first_value()
och last_value()
, kombinerat med DISTINCT
eller DISTINCT ON
för att få det utan anslutningar och underfrågor:
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);
Notera de anpassade ramarna för fönsterfunktionerna !
Eller så kan du använda grundläggande aggregerade funktioner i en underfråga och 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;
Förutsatt unik (userid, rank)
, annars skulle dina krav vara tvetydiga.
Shichinin no samurai
Per begäran i kommentarerna, samma sak för endast de sista sju raderna per användar-id (eller så många som kan hittas, om det är färre):
Återigen, ett av många möjliga sätt. Men jag tror att detta är en av de kortaste:
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;
Observera den omvända sorteringsordningen. Den första raden är den "nyaste" posten. Jag spänner över en ram med (max.) 7 rader och väljer bara resultaten för den senaste posten med DISTINCT ON
.