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

Tilpasset PostgreSQL-aggregat til cirkulært gennemsnit

Du kan gøre brug af en ARRAY skriv internt. Argumenttype kan stadig være en hvilken som helst numerisk type. Demonstrerer 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}'
); 

Overgangsfunktionen f_circavg() er defineret STRICT , så den ignorerer rækker med NULL input. Det sætter også et tredje array-element til at identificere sæt med en eller flere inputrækker - ellers CASE den sidste funktion returnerer NULL .

Midlertidig tabel til test:

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

Jeg smed en NULL ind værdi for også at teste STRICT magi. Ring til:

SELECT circavg(x) FROM t;

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

Krydstjek:

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

Returnerer det samme. Ser ud til at virke. I test med en større tabel var det sidste udtryk med regulære aggregerede funktioner 4x hurtigere end det tilpassede aggregerede.

Test for nul input rækker / kun NULL input:

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

Returnerer NULL i begge tilfælde.



  1. MySQL-indeks på første del af strengen

  2. Konvertering af sekunder til TT:MM:SS

  3. Hvordan undslipper jeg reserverede ord, der bruges som kolonnenavne? MySQL/Opret tabel

  4. ude af stand til at oprette forbindelse til AWS RDS postgres-instans fra pgadmin4