PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Funzione di aggregazione personalizzata in PostgreSQL

Ci sono molti modi per raggiungere questo obiettivo con le funzioni esistenti. Puoi utilizzare il funzioni della finestra first_value() e last_value() , combinato con DISTINCT o DISTINCT ON per ottenerlo senza join e subquery:

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);

Nota i frame per le funzioni della finestra !

Oppure puoi utilizzare le funzioni di aggregazione di base in una sottoquery e 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;

Assumendo (userid, rank) univoco o le tue esigenze sarebbero ambigue.

Demo di SQL Fiddle.

Shichinin nessun samurai


Per richiesta nei commenti, lo stesso solo per le ultime sette righe per userid (o quanti se ne possono trovare, se sono di meno):

Ancora una volta, uno dei tanti modi possibili. Ma credo che questo sia uno dei più brevi:

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;

Notare l'ordinamento invertito. La prima riga è la voce "più recente". Mi occupo di un frame di (max.) 7 righe e scelgo solo i risultati per la voce più recente con DISTINCT ON .

Demo di SQL Fiddle.