sql >> Database >  >> RDS >> PostgreSQL

Aangepast PostgreSQL-aggregaat voor circulair gemiddelde

U kunt gebruik maken van een ARRAY intern typen. Het argumenttype kan nog steeds elk numeriek type zijn. Demonstreren met 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}'
);

De overgangsfunctie f_circavg() is gedefinieerd STRICT , dus het negeert rijen met NULL invoer. Het stelt ook een derde array-element in om sets met een of meer invoerrijen te identificeren - anders de CASE de laatste functie retourneert NULL .

Tijdelijke tabel om te testen:

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

Ik gooide een NULL . in waarde om ook de STRICT . te testen magie. Bel:

SELECT circavg(x) FROM t;

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

Kruiscontrole:

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

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

Geeft hetzelfde terug. Lijkt te werken. In een test met een grotere tabel was de laatste uitdrukking met reguliere aggregatiefuncties 4x sneller dan de aangepaste aggregatie.

Test voor nul invoerrijen / alleen NULL-invoer:

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

Retourneert NULL in beide gevallen.



  1. ORA-29283:ongeldige bestandsbewerking ORA-06512:op SYS.UTL_FILE, regel 536

  2. npm install oracledb geeft fout:kan $OCI_LIB_DIR/libclntsh.dylib niet vinden

  3. Entity Framework EF4.1 - opgeslagen procedure kan niet worden gevonden in de container

  4. NameError:naam '_mysql' is niet gedefinieerd na wijziging in mysql