如何将现有函数(包括聚合)包装到 Postgres 中的新函数中?

Posted

技术标签:

【中文标题】如何将现有函数(包括聚合)包装到 Postgres 中的新函数中?【英文标题】:How to wrap existing functions (including aggregates) into a new one in Postgres? 【发布时间】:2014-06-04 19:51:03 【问题描述】:

我正在使用 Postgres 9.2 生成一些 JSON 数据。对于每个嵌套表,我都在做这组嵌套函数:

SELECT array_to_json(
  coalesce(
    array_agg(
      row_to_json(foo)),
    ARRAY[]::json[])
)
FROM foo

效果是创建一个json数组,每一行都是该行的json集合。如果表为空,则合并确保我得到一个空数组而不是 nil。在大多数情况下, foo 实际上是一个子查询,但我认为这与问题无关。

我想创建一个函数table_to_json_array(expression),这样就和上面的效果一样:

SELECT table_to_json_array(foo) FROM foo

我需要使用这个批次,所以我打算创建一个 Postgres 函数来组合这些调用来清理我的查询。查看文档似乎我需要创建一个聚合而不是一个函数来获取表参数,但那些看起来我需要自己重新实现 array_agg

我是否遗漏了什么(可能只是函数需要采用的类型)?有什么建议吗?

【问题讨论】:

【参考方案1】:

在大多数情况下 foo 实际上是一个子查询,但我不认为那是 与问题相关。

不幸的是,它是。您可以使用 regclass 参数创建函数:

create or replace function table_to_json(source regclass)
returns json language plpgsql
as $$
declare
    t json;
begin
    execute format ('
        SELECT
            array_to_json(
                coalesce(array_agg(row_to_json(%s)),
                ARRAY[]::json[]))
        FROM %s', source, source)
        into t;
    return t;
end $$;

select table_to_json('my_table');
select table_to_json('my_schema.my_view');

但在上下文中:

select table_to_json_rec(arg)
from (select * from my_table) arg

参数 arg 的类型是 record。 PL/pgSQL 函数不能接受类型记录。获得这个的唯一方法是 C 函数,我猜这不是一个选项。聚合也是如此(您必须具有定义聚合的函数)。

【讨论】:

regclass 值的文本表示会在需要时自动引用,因此它必须是 format('.. %s ..', source)%I 将是错误的,并且对于必须引用的标识符会失败。 Details here. 谢谢,来源是第一版中的文字。 从你的回答来看,你知道细节。我将评论留给公众,因为这是一个常见的错误。【参考方案2】:

Postgres 9.3 添加了一个 json_agg 函数,它简化了我需要的特定查询,尽管这不是聚合函数问题的一般解决方案。它仍然需要一个 coalesce 函数来确保正确返回空集。

SELECT coalesce( json_agg(foo), json'[]')
FROM foo

即使 foo 是子查询,它也可以工作。

【讨论】:

以上是关于如何将现有函数(包括聚合)包装到 Postgres 中的新函数中?的主要内容,如果未能解决你的问题,请参考以下文章

POSTGRES Group BY中的聚合函数

postgres 按聚合函数分组

如何将docker容器添加到现有docker网络

在 Postgres 中的数组字段上应用聚合函数?

使用 sqlalchemy 将 onupdate="cascade" 添加到 postgres 中的现有列

Postgres XL 将数据节点添加到现有集群