问题描述
我正在尝试从我从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);
,
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()
具有一些小凹坑:
-
我也不会将其命名为“ range_merge”,它也是普通函数
range_merge()
的名称。虽然这是合法的,但仍然会引起混乱的错误。 -
您知道函数
range_merge()
在输出范围内的输入范围之间包含间隔吗? -
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
相关: