Es gibt viele Möglichkeiten, dies mit vorhandenen Funktionen zu erreichen. Sie können den vorhandenen Fensterfunktionen first_value()
und last_value()
, kombiniert mit DISTINCT
oder DISTINCT ON
um es ohne Verknüpfungen und Unterabfragen zu erhalten:
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);
Beachten Sie die benutzerdefinierten Rahmen für die Fensterfunktionen !
Oder Sie können grundlegende Aggregatfunktionen in einer Unterabfrage und JOIN verwenden:
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;
Unter der Annahme eines eindeutigen (userid, rank)
, oder Ihre Anforderungen wären mehrdeutig.
Shichinin kein Samurai
Auf Anfrage in den Kommentaren, dasselbe nur für die letzten sieben Zeilen pro Benutzer-ID (oder so viele wie gefunden werden können, wenn es weniger sind):
Wieder einer von vielen möglichen Wegen. Aber ich glaube, das ist eines der kürzesten:
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;
Beachten Sie die umgekehrte Sortierreihenfolge. Die erste Zeile ist der "neueste" Eintrag. Ich spanne einen Rahmen von (max.) 7 Zeilen auf und picke nur die Ergebnisse für den neusten Eintrag mit DISTINCT ON
heraus .