自定义PostgreSQL聚合为循环平均值

时间:2012-04-19 09:36:40

标签: postgresql types aggregate-functions

我正在尝试在Postgres中实现一个自定义聚合函数,它将以度为单位平均方向 - 即我希望能够做到:

SELECT circavg(direction) FROM sometable;

这可以使用公式来完成:

xbar = atan2(sum(sin(xi), sum(cos(xi)))

我想我需要定义一个sfunc,它将指向一个方向,并将其正弦和余弦添加到两个累加器中。最后一个函数然后使用atan2将两个组件转换回方向。

我无法弄清楚如何定义sfunc,以便当前状态包含两个组件,例如(float, float)。文档在具体示例上有点简短,所以感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

您可以在内部使用 ARRAY 类型。参数类型仍然可以是任何数字类型。使用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}'
);

转换函数f_circavg()已定义为STRICT,因此它会忽略输入NULL的行。它还设置第三个数组元素来标识具有一个或多个输入行的集合 - 否则CASE最终函数返回NULL

用于测试的临时表:

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

我投入NULL值来测试STRICT魔法。拨打:

SELECT circavg(x) FROM t;

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

交叉检查:

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

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

返回相同的内容。似乎工作。在使用更大的表进行测试时,具有常规聚合函数的最后一个表达式比自定义聚合快4倍。

测试零输入行/仅NULL输入:

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

在这两种情况下都会返回NULL

答案 1 :(得分:0)

PostgreSQL为您提供了一组geometry typesPOINT作为基础。{ 使用此类型作为函数的输入参数。

如果您愿意,可以创建custom type作为替代方案。