Hay muchas maneras de lograr esto con las funciones existentes. Puede usar el funciones de ventana first_value()
y last_value()
, combinado con DISTINCT
o DISTINCT ON
para obtenerlo sin uniones ni subconsultas:
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);
Tenga en cuenta los marcos personalizados para las funciones de ventana !
O puede usar funciones agregadas básicas en una subconsulta y UNIRSE:
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;
Suponiendo (userid, rank)
, o sus requisitos serían ambiguos.
Shichinin no samurái
Por solicitud en los comentarios, lo mismo solo para las últimas siete filas por ID de usuario (o tantos como se puedan encontrar, si hay menos):
Una vez más, una de las muchas formas posibles. Pero creo que este es uno de los más cortos:
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;
Tenga en cuenta el orden de clasificación invertido. La primera fila es la entrada "más nueva". Abarco un marco de (máx.) 7 filas y selecciono solo los resultados de la entrada más reciente con DISTINCT ON
.