PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Função de agregação personalizada no PostgreSQL


Há muitas maneiras de fazer isso com as funções existentes. Você pode usar o funções de janela first_value() e last_value() , combinado com DISTINCT ou DISTINCT ON para obtê-lo sem junções e 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);

Observe os quadros personalizados para as funções da janela !

Ou você pode usar funções agregadas básicas em uma subconsulta 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;

Assumindo exclusivo (userid, rank) , ou seus requisitos seriam ambíguos.

Demonstração do SQL Fiddle.

Shichinin no samurai



Por solicitação nos comentários, o mesmo para apenas as últimas sete linhas por ID de usuário (ou quantos puderem ser encontrados, se houver menos):

Novamente, uma das muitas maneiras possíveis. Mas acredito que este seja um dos mais curtos:
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;

Observe a ordem de classificação invertida. A primeira linha é a entrada "mais recente". Eu abro um quadro de (máx.) 7 linhas e escolho apenas os resultados para a entrada mais recente com DISTINCT ON .

Demonstração do SQL Fiddle.