sql >> Base de Datos >  >> RDS >> PostgreSQL

Función agregada personalizada en PostgreSQL

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.

Demostración de SQL Fiddle.

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 .

Demostración de SQL Fiddle.