PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Fonction d'agrégation personnalisée dans PostgreSQL

Il existe de nombreuses façons d'y parvenir avec les fonctions existantes. Vous pouvez utiliser le fonctions de fenêtre first_value() et last_value() , combiné avec DISTINCT ou DISTINCT ON pour l'obtenir sans jointures ni sous-requêtes :

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

Notez les cadres personnalisés pour les fonctions de fenêtre !

Ou vous pouvez utiliser des fonctions d'agrégation de base dans une sous-requête et 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;

En supposant un (userid, rank) unique , ou vos exigences seraient ambiguës.

Démo SQL Fiddle.

Shichinin pas de samouraï


Par demande dans les commentaires, idem uniquement pour les sept dernières lignes par ID utilisateur (ou autant qu'il est possible d'en trouver, s'il y en a moins) :

Encore une fois, l'une des nombreuses façons possibles. Mais je crois que c'est l'un des plus courts :

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;

Notez l'ordre de tri inversé. La première ligne est l'entrée "la plus récente". Je couvre un cadre de (max.) 7 lignes et sélectionne uniquement les résultats de l'entrée la plus récente avec DISTINCT ON .

Démo SQL Fiddle.