Er zijn veel manieren om dit te bereiken met bestaande functies. U kunt de bestaande vensterfuncties first_value()
en last_value()
, gecombineerd met DISTINCT
of DISTINCT ON
om het te krijgen zonder joins en subquery's:
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);
Let op de aangepaste frames voor de vensterfuncties !
Of u kunt elementaire aggregatiefuncties in een subquery gebruiken en 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;
Uitgaande van unieke (userid, rank)
, of uw vereisten zouden dubbelzinnig zijn.
Shichinin geen samoerai
Per verzoek in de opmerkingen, hetzelfde voor alleen de laatste zeven rijen per gebruikers-ID (of zoveel als er gevonden kunnen worden, als er minder zijn):
Nogmaals, een van de vele mogelijke manieren. Maar ik geloof dat dit een van de kortste is:
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;
Let op de omgekeerde sorteervolgorde. De eerste rij is de "nieuwste" invoer. Ik omspan een frame van (max.) 7 rijen en kies alleen de resultaten voor het nieuwste item met DISTINCT ON
.