从一组条目计算聚合的tsrange?

问题描述

我正在尝试从我从SQL查询提取的一组行中计算聚合的tsrange。问题是我不断收到输入参数未传递的错误

CREATE OR REPLACE AGGREGATE range_merge(anyrange)
(
    sfunc = range_merge,stype = anyrange
);

DROP FUNCTION IF EXISTS aggregate_validity(entity_name regclass,entry bigint);

CREATE OR REPLACE FUNCTION aggregate_validity(entity_name regclass,entry bigint) returns tsrange AS
$$
DECLARE
    result tsrange;
BEGIN
   EXECUTE format('select range_merge(valid) from %s where entity_id = %U',entity_name,entry) into result;
   return result;
END
$$ LANGUAGE plpgsql;

当我这样做时:

select * from aggregate_validity(country,1);

我收到一条错误消息,指出实体名称和条目不存在。似乎无法正确地将输入参数化为语句。

解决方法

功能:

EXECUTE format('select range_merge(valid) from %s where entity_id=%U',entity_name,entry) 
into result;
=>
EXECUTE format('select range_merge(valid) from %I where entity_id=%s',entry) 
into result;
--%I for identifier,%s for value

致电:

select * from aggregate_validity(country,1)
=>
select * from aggregate_validity('country',1);

db<>fiddle demo

,
CREATE OR REPLACE AGGREGATE range_merge(anyrange) (
   SFUNC = range_merge,STYPE = anyrange
);

-- DROP FUNCTION IF EXISTS aggregate_validity(entity_name regclass,entry bigint);
CREATE OR REPLACE FUNCTION aggregate_validity(entity_name regclass,entry bigint,OUT result tsrange)
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE 'SELECT range_merge(valid) FROM ' || entity_name || ' WHERE entity_id = $1'
   INTO result
   USING entry;
END
$func$;

致电:

SELECT aggregate_validity('country',1);

db 提琴here

该调用不需要SELECT * FROM,因为该函数将为每个定义返回一个值。

我使用了OUT参数来简化(OUT result tsrange)。参见:

不要将entry值连接到SQL字符串中。使用USING子句将其作为 value 传递。更干净,更快。

由于entity_name作为regclass进行传递,因此简单地串联起来是安全的(这便宜一些)。参见:

此外,如Lukasz已经提供的那样,缺少引号和格式说明不正确。

您的自定义聚合函数range_merge()具有一些小凹坑

  1. 我也不会将其命名为“ range_merge”,它也是普通函数range_merge()的名称。虽然这是合法的,但仍然会引起混乱的错误。

  2. 您知道函数range_merge() 在输出范围内的输入范围之间包含间隔吗?

  3. range_merge()对于任何NULL输入都返回NULL。因此,如果您的表在列valid中有任何NULL值,则结果始终为NULL。我强烈建议将任何涉及的列定义为NOT NULL

如果您愿意安装其他模块,请考虑range_agg的Paul Jungwirth的also here on Stackovflow。它提供了高级功能range_agg(),可以解决其中提到的一些问题。

如果您不想包含空格,请考虑Postgres Wiki page on range aggregation.

我可能 完全使用aggregate_validity()。它掩盖了Postgres查询计划程序的嵌套功能,并且可能导致次优查询计划。通常,您可以用相关或LATERAL子查询代替它,Postgres可以在外部查询的上下文中对其进行计划和优化。我在小提琴上附加了一个演示:

db 提琴here

相关: