从一组条目计算聚合的 tsrange?
Compute an aggregated tsrange from a set of entries?
我正在尝试根据从 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',entity_name, 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 = '
INTO result
USING entry;
END
$func$;
致电:
SELECT aggregate_validity('country', 1);
db<>fiddle here
调用不需要 SELECT * FROM
,因为函数 returns 每个定义一个值。
我使用了一个 OUT
参数来简化 (OUT result tsrange
)。参见:
- Returning from a function with OUT parameter
不要将 entry
值连接到 SQL 字符串中。使用 USING
子句将其作为 value 传递。更干净,更快。
由于 entity_name
作为 regclass
传递,因此简单地连接是安全的(这会便宜一些)。参见:
- Table name as a PostgreSQL function parameter
另外,缺少引号和格式说明符不正确,正如 Lukasz 已经提供的那样。
您的自定义聚合函数 range_merge()
有一些 注意事项:
我不会将它命名为“range_merge”,那也是普通函数 range_merge()
的名称。虽然这是合法的,但它仍然会引起令人困惑的错误。
您知道函数 range_merge()
在输出范围中包含 输入范围之间的间隙吗?
range_merge()
returns NULL 对于任何 NULL 输入。因此,如果您的 table 在列 valid
中有任何 NULL 值,则结果始终为 NULL。我强烈建议任何涉及的列都应定义为 NOT NULL
.
如果您可以随意安装其他模块,请考虑 range_agg by Paul Jungwirth who is also here on Stackovflow。它提供了卓越的功能 range_agg()
解决了一些提到的问题。
如果您不想包含空白,请考虑 Postgres Wiki page on range aggregation.
我可能 不会 使用 aggregate_validity()
。它掩盖了 Postgres 查询计划器的嵌套功能,并可能导致次优的查询计划。通常,您可以将其替换为 相关或 LATERAL
子查询 ,Postgres 可以在外部查询的上下文中对其进行规划和优化。我在 fiddle:
中附加了一个演示
db<>fiddle here
相关:
我正在尝试根据从 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',entity_name, 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 = '
INTO result
USING entry;
END
$func$;
致电:
SELECT aggregate_validity('country', 1);
db<>fiddle here
调用不需要 SELECT * FROM
,因为函数 returns 每个定义一个值。
我使用了一个 OUT
参数来简化 (OUT result tsrange
)。参见:
- Returning from a function with OUT parameter
不要将 entry
值连接到 SQL 字符串中。使用 USING
子句将其作为 value 传递。更干净,更快。
由于 entity_name
作为 regclass
传递,因此简单地连接是安全的(这会便宜一些)。参见:
- Table name as a PostgreSQL function parameter
另外,缺少引号和格式说明符不正确,正如 Lukasz 已经提供的那样。
您的自定义聚合函数 range_merge()
有一些 注意事项:
我不会将它命名为“range_merge”,那也是普通函数
range_merge()
的名称。虽然这是合法的,但它仍然会引起令人困惑的错误。您知道函数
range_merge()
在输出范围中包含 输入范围之间的间隙吗?range_merge()
returns NULL 对于任何 NULL 输入。因此,如果您的 table 在列valid
中有任何 NULL 值,则结果始终为 NULL。我强烈建议任何涉及的列都应定义为NOT NULL
.
如果您可以随意安装其他模块,请考虑 range_agg by Paul Jungwirth who is also here on Stackovflow。它提供了卓越的功能 range_agg()
解决了一些提到的问题。
如果您不想包含空白,请考虑 Postgres Wiki page on range aggregation.
我可能 不会 使用 aggregate_validity()
。它掩盖了 Postgres 查询计划器的嵌套功能,并可能导致次优的查询计划。通常,您可以将其替换为 相关或 LATERAL
子查询 ,Postgres 可以在外部查询的上下文中对其进行规划和优化。我在 fiddle:
db<>fiddle here
相关: