【问题标题】:Custom PostgreSQL aggregate for circular average用于循环平均的自定义 PostgreSQL 聚合
【发布时间】:2012-04-19 09:36:39
【问题描述】:

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

SELECT circavg(direction) FROM sometable;

这可以使用公式来完成:

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

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

我不知道如何定义 sfunc 以便当前状态由 两个 组件组成,例如(float, float)。文档中的具体示例有点短,因此感谢您提供任何帮助。

【问题讨论】:

  • 欢迎来到 SO!您描述的 circavg 采用单个参数,而您在 xbar 示例中指定了 2 个参数。此外,您错过了示例中的右括号。
  • @vyegorov:xbar 示例确实只有一个参数 (xi),但它在两个地方使用。

标签: postgresql types aggregate-functions


【解决方案1】:

您可以在内部使用 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

【讨论】:

  • 如果没有行返回0。它应该返回NULL
  • @user:我改进了自定义聚合函数,使其也适用于无行和/或 NULL 值输入。 (我最喜欢的是使用常规聚合函数的更快解决方案。)
  • 非常感谢。我已经发布了一个相关的问题。如果你能看看就太好了。 stackoverflow.com/q/54829781/512251
【解决方案2】:

PostgreSQL 为您提供了一组geometry typesPOINT 是最基本的。
将此类型用作函数的输入参数。

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

【讨论】:

    猜你喜欢
    • 2021-08-31
    • 2014-09-07
    • 2015-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-08
    • 2018-07-03
    • 1970-01-01
    相关资源
    最近更新 更多