sql >> Databasteknik >  >> RDS >> PostgreSQL

Anpassat PostgreSQL-aggregat för cirkulärt genomsnitt

Du kan använda en ARRAY typ internt. Argumenttyp kan fortfarande vara vilken numerisk typ som helst. Demonstrerar med float (=double precision ):

CREATE OR REPLACE FUNCTION f_circavg (float[], float)
  RETURNS float[] LANGUAGE sql STRICT AS
'SELECT ARRAY[$1[1] + sin($2), $1[2] + cos($2), 1]';

CREATE OR REPLACE FUNCTION f_circavg_final (float[])
  RETURNS float  LANGUAGE sql AS
'SELECT CASE WHEN $1[3] > 0 THEN atan2($1[1], $1[2]) END';

CREATE AGGREGATE circavg (float) (
   sfunc     = f_circavg
 , stype     = float[]
 , finalfunc = f_circavg_final
 , initcond  = '{0,0,0}'
);

Övergångsfunktionen f_circavg() är definierad STRICT , så den ignorerar rader med NULL inmatning. Den ställer också in ett tredje arrayelement för att identifiera uppsättningar med en eller flera inmatningsrader - annars CASE den sista funktionen returnerar NULL .

Tillfällig tabell för testning:

CREATE TEMP TABLE t (x float);
INSERT INTO t VALUES (2), (NULL), (3), (4), (5);

Jag slängde in en NULL värde för att även testa STRICT magi. Ring:

SELECT circavg(x) FROM t;

       circavg
-------------------
 -2.78318530717959

Korskontroll:

SELECT atan2(sum(sin(x)), sum(cos(x))) FROM t;

       atan2
-------------------
 -2.78318530717959

Returnerar detsamma. Verkar fungera. I test med en större tabell var det senaste uttrycket med vanliga aggregatfunktioner 4 gånger snabbare än det anpassade aggregatet.

Testa för nollinmatningsrader / endast NULL-ingång:

SELECT circavg(x) FROM t WHERE false;     -- no input rows
SELECT circavg(x) FROM t WHERE x IS NULL; -- only NULL input

Returnerar NULL i båda fallen.



  1. Anropar PL/SQL-procedur med användardefinierad post som IN-parameter med JDBC

  2. cakephp Tabell för modell hittades inte i datakällans standard

  3. MySQL regexp mycket långsam än liknande

  4. Infoga sökvägen till en fil med \\ i mysql med java