是否可以在 Postgres 中包装聚合函数?

Noa*_*ter 7 postgresql aggregate functions

Postgres 的 string_agg(expr, delimiter) 函数很棒。但我想要一个版本,它接受一个参数——要聚合的字段——并假设分隔符为 ', ' 因为这是我想要的 10 次中的 9 次。使用非聚合函数,我可以只需这样做:

create or replace function public.string_agg(text)
returns text
as $$
    select string_agg($1, ', ');
$$ language sql
immutable;
Run Code Online (Sandbox Code Playgroud)

但由于 string_agg 是一个聚合函数,这不起作用。它抱怨我传递给它的字段需要在 GROUP BY 子句中,这告诉我查询引擎不知道我的包装器是一个聚合函数。

我查看了用户定义聚合的文档(http://www.postgresql.org/docs/9.1/static/xaggr.html 和http://www.postgresql.org/docs/9.1/static/sql-createaggregate .html ) 但我不清楚如何使用现有的 string_agg(text, text) 定义我的新 string_agg(text)。看来我必须从头开始定义我的新函数,这比我想承担的要复杂得多,而且我也不完全有信心我可以完美地反映内置 string_agg 的行为。

那么是否有一些技术可以创建一个我没有看到的简单包装器?或者我将不得不做更多的工作?

Erw*_*ter 3

据我所知,您无法包装聚合函数。您必须编写自己的聚合函数。

如果您编写自己的函数,则在升级或移植到另一个数据库时可能会遇到不兼容的情况。因此,就我个人而言,我不会打扰,只需string_agg()在每次调用时添加分隔符即可。其实并没有那么痛苦。

也就是说,编写自己的聚合函数也不那么复杂:

自定义最终函数

CREATE FUNCTION f_str_agg_final(anyarray)
    RETURNS text LANGUAGE SQL AS
$func$SELECT array_to_string($1, ', ')$func$;
Run Code Online (Sandbox Code Playgroud)

总计:

CREATE AGGREGATE f_str_agg (anyelement) (
    SFUNC     = array_append
   ,STYPE     = anyarray
   ,INITCOND  = '{}'
   ,FINALFUNC = f_str_agg_final
);
Run Code Online (Sandbox Code Playgroud)

称呼:

SELECT f_str_agg (kat) from tbl;
Run Code Online (Sandbox Code Playgroud)

适用于几乎任何类型 - 除了数组类型。您必须为此修改您的聚合。更多内容请参见关于 SO 的密切相关答案