Der er mange måder at opnå dette på med eksisterende funktioner. Du kan bruge den eksisterende vinduefunktioner first_value()
og last_value()
, kombineret med DISTINCT
eller DISTINCT ON
for at få det uden joins og underforespørgsler:
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);
Bemærk de brugerdefinerede rammer til vinduesfunktionerne !
Eller du kan bruge grundlæggende aggregerede funktioner i en underforespørgsel og 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;
Forudsat unik (userid, rank)
, ellers ville dine krav være tvetydige.
Shichinin no samurai
Per anmodning i kommentarerne, det samme for kun de sidste syv rækker pr. bruger-id (eller så mange som kan findes, hvis der er færre):
Igen, en af mange mulige måder. Men jeg tror, at dette er en af de korteste:
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;
Bemærk den omvendte sorteringsrækkefølge. Den første række er den "nyeste" post. Jeg spænder over en ramme på (maks.) 7 rækker og vælger kun resultaterne for den nyeste post med DISTINCT ON
.