0

in order to create a more complex custom aggregate function, i followed first this amazing tutorial.

Here the data i use :

create table entries(
  id serial primary key,
  amount float8 not null
);

select setseed(0);

insert into entries(amount)
select (2000 * random()) - 1000
from generate_series(1, 1000000);

So I have this table :

 id      |        amount         |   running_total
---------+-----------------------+--------------------
       1 |     -462.016298435628 |  -462.016298435628
       2 |      162.440904416144 |  -299.575394019485
       3 |     -820.292402990162 |  -1119.86779700965
       4 |     -866.230697371066 |  -1986.09849438071
       5 |      -495.30001822859 |   -2481.3985126093
       6 |      772.393747232854 |  -1709.00476537645
       7 |     -323.866365477443 |  -2032.87113085389
       8 |     -856.917716562748 |  -2889.78884741664
       9 |      285.323366522789 |  -2604.46548089385
      10 |     -867.916810326278 |  -3472.38229122013
-- snip --

And I would like the max of the running_total column
(I know I can do do it without a new aggregate function, but it's for the demonstration)

So i've made this aggregate function

create or replace function grt_sfunc(agg_state point, el float8)
returns point
immutable
language plpgsql
as $$
declare
  greatest_sum float8;
  current_sum float8;
begin
    current_sum := agg_state[0] + el;
    greatest_sum := 40;
    /*if agg_state[1] < current_sum then
        greatest_sum := current_sum;
    else
        greatest_sum := agg_state[1];
    end if;*/
    return point(current_sum, greatest_sum);
    /*return point(3.14159, 0);*/
end;
$$;

create or replace function grt_finalfunc(agg_state point)
returns float8
immutable
strict
language plpgsql
as $$
begin
  return agg_state[0];
end;
$$;

create or replace aggregate greatest_running_total (float8)
(
    sfunc = grt_sfunc,
    stype = point,
    finalfunc = grt_finalfunc
);

Normally it sould work, but in the end, it gives me a null result :

select greatest_running_total(amount order by id asc)
from entries;


id    |  running_total
---------+---------------
    1 |  [NULL]

I tried to change the type of the data, to check the 2 first aggregate functions separately, they are working well. Does someone could help me find a solution please ? :)

Thank you very much !

2
  • Any number + null = null. Only add non-null values. Commented Mar 29, 2021 at 14:10
  • I only add non-null values :/ But I think I found the problem, there's no initial condition !! So the first value is null !! Thank you ;) Commented Mar 29, 2021 at 14:31

2 Answers 2

3

You need to set a non-NULL initcond for the aggregate. Presumably that would be (0,0), or maybe negative very large numbers for each? Or manually check for the agg_state being NULL.

Also, it seems like your grt_finalfunc should be returning subscript [1], not [0].

Sign up to request clarification or add additional context in comments.

Comments

0

So, the solution was to add an initial condition. Indeed, without initial condition, the first value is considered as NULL :D (thank you @jjanes and @The Impaler)

So I corrected ma aggregated function :

create or replace aggregate greatest_running_total (float8)
(
    sfunc = grt_sfunc,
    stype = point,
    finalfunc = grt_finalfunc,
    initcond = '(0,0)'
);

And, indeed SQL indexes its tables from 1 and not from 0... Here was my second mistake,

Thank you very much !!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.