为 Postgres 编写自定义聚合函数

发布于 2025-01-15 13:41:08 字数 586 浏览 3 评论 0原文

我想编写一个聚合函数,返回格式如下的文本: min ->整数列的最大值,其中 min 和 max 是该列的最小值和最大值。 例如:

SELECT min_to_max(val) FROM (VALUES(5),(3),(6),(7),(9),(10),(7)) t(val);

会返回

min_to_max
-----------
3 -> 10

我尝试使用游标编写,但我认为使用自定义聚合会更好,但我不知道如何编写自定义聚合。

我所做的是编写一个正常的函数:

create or replace function min_to_max()
returns varchar
language plpgsql
as
$$
declare
   answer varchar;
begin
   select MIN(val) || '->' ||  max(val)
   into answer
   from abc;

return answer;
end;
$$;

I want to write an aggregate function that returns a text formatted like: min -> max for an integer column, where
min and max are minimum and maximum values of that column.
For example:

SELECT min_to_max(val) FROM (VALUES(5),(3),(6),(7),(9),(10),(7)) t(val);

would return

min_to_max
-----------
3 -> 10

I tried writing using a cursor but I think using a custom aggregate would be much better but I'm clueless how to write a custom aggregate.

What I have done is written a normal function:

create or replace function min_to_max()
returns varchar
language plpgsql
as
$
declare
   answer varchar;
begin
   select MIN(val) || '->' ||  max(val)
   into answer
   from abc;

return answer;
end;
$;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

月亮邮递员 2025-01-22 13:41:08

为什么需要聚合函数? MIN() 和 MAX() 工作正常:

SELECT MIN(val) || '->' ||  max(val) FROM (VALUES(5),(3),(6),(7),(9),(10),(7)) t(val);

Why do you need an aggregate function? MIN() and MAX() work fine:

SELECT MIN(val) || '->' ||  max(val) FROM (VALUES(5),(3),(6),(7),(9),(10),(7)) t(val);
水波映月 2025-01-22 13:41:08

正如您所怀疑的,您尝试了一个标准函数,但这只是定义聚合的一部分。用户定义的聚合基本上需要定义(创建聚合)和2个函数,一个定义状态到状态转换的函数和一个处理最终结果生成的函数。 (查看演示

-- function to manage the state to state transition 
create or replace 
 function uagg_m2m (cagg bigint[], cval int)
   returns bigint[]
  language plpgsql
    strict
as $
-- SFUNC for min_to_max AGGREGATE
declare nagg bigint[]; 
begin
    nagg[1] = least(cval::bigint, cagg[1]);
    nagg[2] = greatest(cval::bigint, cagg[2]);
    return nagg; 
end;
$; 

-- function to manaage the final output
create or replace 
 function uagg_m2m_fin (cagg bigint[])
   returns text
  language plpgsql
as $
--  FINALFUNC for min_to_max AGGREGATE 
declare agg int[] = '{null,null}';
begin
     -- if the low value is = to initialization value 
     -- it means that all values for a state translation were null
     -- in that case then 
     if cagg[1] <> 2147483648 then 
        agg[1] = cagg[1]::int;
        agg[2] = cagg[2]::int;
     end if;
    
     return agg[1] || ' -> ' || agg[2]; 
end;
$;

-- define user aggregate
create or replace  aggregate  min_to_max (p_val integer)
    (
      sfunc = uagg_m2m                       -- state-to-state transition function  
    , stype = bigint[]                       -- array with 2 elements representing min, max.
    , finalfunc = uagg_m2m_fin               -- final result handling function   
    , initcond = '{2147483648, -2147483649}' -- initial state, array of (min, max) 
    ); 

As suspected you attempted a standard function, however this is only part of defining an aggregate. User defined aggregate requires basically the definition (create aggregate) and 2 functions, one function to define the state-to-state transition and one function to handle the production of the final result. (see demo)

-- function to manage the state to state transition 
create or replace 
 function uagg_m2m (cagg bigint[], cval int)
   returns bigint[]
  language plpgsql
    strict
as $
-- SFUNC for min_to_max AGGREGATE
declare nagg bigint[]; 
begin
    nagg[1] = least(cval::bigint, cagg[1]);
    nagg[2] = greatest(cval::bigint, cagg[2]);
    return nagg; 
end;
$; 

-- function to manaage the final output
create or replace 
 function uagg_m2m_fin (cagg bigint[])
   returns text
  language plpgsql
as $
--  FINALFUNC for min_to_max AGGREGATE 
declare agg int[] = '{null,null}';
begin
     -- if the low value is = to initialization value 
     -- it means that all values for a state translation were null
     -- in that case then 
     if cagg[1] <> 2147483648 then 
        agg[1] = cagg[1]::int;
        agg[2] = cagg[2]::int;
     end if;
    
     return agg[1] || ' -> ' || agg[2]; 
end;
$;

-- define user aggregate
create or replace  aggregate  min_to_max (p_val integer)
    (
      sfunc = uagg_m2m                       -- state-to-state transition function  
    , stype = bigint[]                       -- array with 2 elements representing min, max.
    , finalfunc = uagg_m2m_fin               -- final result handling function   
    , initcond = '{2147483648, -2147483649}' -- initial state, array of (min, max) 
    ); 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文