window 的自定义 Greenplum 聚合函数
Custom Greenplum aggregate function with window
我正在使用 Greenplum DB,我想计算 window 中的中位数,例如:
SELECT avg(var1) OVER (PARTITION BY var2 ORDER BY datetime
ROWS BETWEEN 10 PRECEDING AND CURRENT ROW) FROM tbl...
不幸的是,中位数在 Postgres 中没有实现,所以我使用这个例子创建了我自己的聚合:
https://wiki.postgresql.org/wiki/Aggregate_Median
问题是,当我使用整个列但不在 window(带有 OVER 子句)中时,这会起作用,返回应该定义 'prefunc' 的错误。 Greenplum 文档确认:
http://gpdb.docs.pivotal.io/4380/ref_guide/sql_commands/CREATE_AGGREGATE.html
prefunc的文档和作用我不是很清楚。您有定义支持 windows 的自定义 Postgres 聚合函数的示例吗?
我不知道这是否适用于 Greenplum。但是,在现代版本的 Postgres 中,您可以将 array_agg()
用作 window 函数。因此,对于您的特定问题,运行 中位数是:
select (array_agg(var1) over (partition by var2 order by datetime
rows between 10 preceding and current row
)[6] as running_median
编辑:
另一种方法是使用子查询:
select t.*,
(select t2.var1
from t t2
where t2.var2 = t.var2 and t2.datetime < t.datetime
order by t2.datetime desc
offset 5 limit 1
) running_median
from t;
要在 GPDB 中创建自定义聚合,您需要定义一个 PREFUNC,这不是常规 Postgres 中的参数。
在普通的 Postgres 中,聚合需要一个起始状态(例如 STYPE=numeric[]
)和一个告诉它如何将新项目添加到当前状态的函数(例如 SFUNC=array_append
)。但是在像 GPDB 这样的分布式系统中,它在节点之间移动数据,一个节点从两个地方(即两个数组)接收状态应该如何组合两个状态?这就是 PREFUNC 的作用。然后,最后可以在单个组合状态上调用 FINALFUNC 并返回。
在计算中位数的示例中,您需要做的就是将 PREFUNC=array_cat,
添加到您从 median example code 中获取的聚合定义中。 array_cat
采用两个数组,returns 将它们作为一个组合数组。我试过了,它对我有用,既可以作为聚合,也可以作为 window。
(请注意,采用 numeric[]
的版本有效,但由于某种原因而不是 anyarray
版本。似乎是出于对创建 window/aggregate函数。)
有关聚合的更多信息,请参阅 Lukasz 提到的 GPDB docs。
我正在使用 Greenplum DB,我想计算 window 中的中位数,例如:
SELECT avg(var1) OVER (PARTITION BY var2 ORDER BY datetime
ROWS BETWEEN 10 PRECEDING AND CURRENT ROW) FROM tbl...
不幸的是,中位数在 Postgres 中没有实现,所以我使用这个例子创建了我自己的聚合: https://wiki.postgresql.org/wiki/Aggregate_Median
问题是,当我使用整个列但不在 window(带有 OVER 子句)中时,这会起作用,返回应该定义 'prefunc' 的错误。 Greenplum 文档确认: http://gpdb.docs.pivotal.io/4380/ref_guide/sql_commands/CREATE_AGGREGATE.html
prefunc的文档和作用我不是很清楚。您有定义支持 windows 的自定义 Postgres 聚合函数的示例吗?
我不知道这是否适用于 Greenplum。但是,在现代版本的 Postgres 中,您可以将 array_agg()
用作 window 函数。因此,对于您的特定问题,运行 中位数是:
select (array_agg(var1) over (partition by var2 order by datetime
rows between 10 preceding and current row
)[6] as running_median
编辑:
另一种方法是使用子查询:
select t.*,
(select t2.var1
from t t2
where t2.var2 = t.var2 and t2.datetime < t.datetime
order by t2.datetime desc
offset 5 limit 1
) running_median
from t;
要在 GPDB 中创建自定义聚合,您需要定义一个 PREFUNC,这不是常规 Postgres 中的参数。
在普通的 Postgres 中,聚合需要一个起始状态(例如 STYPE=numeric[]
)和一个告诉它如何将新项目添加到当前状态的函数(例如 SFUNC=array_append
)。但是在像 GPDB 这样的分布式系统中,它在节点之间移动数据,一个节点从两个地方(即两个数组)接收状态应该如何组合两个状态?这就是 PREFUNC 的作用。然后,最后可以在单个组合状态上调用 FINALFUNC 并返回。
在计算中位数的示例中,您需要做的就是将 PREFUNC=array_cat,
添加到您从 median example code 中获取的聚合定义中。 array_cat
采用两个数组,returns 将它们作为一个组合数组。我试过了,它对我有用,既可以作为聚合,也可以作为 window。
(请注意,采用 numeric[]
的版本有效,但由于某种原因而不是 anyarray
版本。似乎是出于对创建 window/aggregate函数。)
有关聚合的更多信息,请参阅 Lukasz 提到的 GPDB docs。