PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Benutzerdefinierte Aggregatfunktion in PostgreSQL

Es gibt viele Möglichkeiten, dies mit vorhandenen Funktionen zu erreichen. Sie können den vorhandenen Fensterfunktionen first_value() und last_value() , kombiniert mit DISTINCT oder DISTINCT ON um es ohne Verknüpfungen und Unterabfragen zu erhalten:

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

Beachten Sie die benutzerdefinierten Rahmen für die Fensterfunktionen !

Oder Sie können grundlegende Aggregatfunktionen in einer Unterabfrage und JOIN verwenden:

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;

Unter der Annahme eines eindeutigen (userid, rank) , oder Ihre Anforderungen wären mehrdeutig.

SQL-Fiddle-Demo.

Shichinin kein Samurai


Auf Anfrage in den Kommentaren, dasselbe nur für die letzten sieben Zeilen pro Benutzer-ID (oder so viele wie gefunden werden können, wenn es weniger sind):

Wieder einer von vielen möglichen Wegen. Aber ich glaube, das ist eines der kürzesten:

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;

Beachten Sie die umgekehrte Sortierreihenfolge. Die erste Zeile ist der "neueste" Eintrag. Ich spanne einen Rahmen von (max.) 7 Zeilen auf und picke nur die Ergebnisse für den neusten Eintrag mit DISTINCT ON heraus .

SQL-Fiddle-Demo.