As Postgresql documentation states in # 36.12.4. Partial Aggregation aggregate functions can support partial aggregation. To do this with custom aggregate function as again the documentation says we have to define COMBINEFUNC. I have tried to do this, but it is never called. Is there any example of how do call this partial aggregation correctly. I didn't find either.
The general idea is that I have for example a table
| type | value |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 2 | 4 |
And I want sum values for each type (eg, for type=1 - 1+2=3 and for type=2 - 3+4=7) and then combine it with by for example multiplying the subset results (eg, 3*7=21).
I thought it could be achieved with partial aggregation but I didn't find how to do this correctly. Or maybe I do it completely wrong?
Update
Adding example SQL
CREATE OR REPLACE FUNCTION my_sum_sfunc(state integer, value integer)
RETURNS integer
LANGUAGE plpgsql
AS $$
BEGIN
RAISE NOTICE 'SUM % + %', state, value;
RETURN state + value;
END;
$$;
CREATE OR REPLACE FUNCTION my_sum_combinefunc(state1 integer, state2 integer)
RETURNS integer
LANGUAGE plpgsql
AS $$
BEGIN
RAISE NOTICE 'COMBINE % * %', state1, state2;
RETURN state1 * state2;
END;
$$;
CREATE AGGREGATE my_sum(integer) (
SFUNC = my_sum_sfunc,
STYPE = integer,
INITCOND = '0',
COMBINEFUNC = my_sum_combinefunc,
PARALLEL = SAFE
);
CREATE TABLE my_table (
id integer PRIMARY KEY,
"type" integer NOT NULL,
value integer
);
INSERT INTO my_table (id, "type", value)
VALUES
(1, 1, 1),
(2, 1, 2),
(3, 2, 3),
(4, 2, 4);
I've tried simple
SELECT my_sum(v.value)
FROM my_table v
Also tried
SELECT my_sum(v.value) OVER (PARTITION BY v."type")
FROM my_table v
None of these makes call to combine function
Update 2 Posting my full bitwise aggregate functions as asked
CREATE OR REPLACE FUNCTION bit_mask_and_state(agg_state integer[], cur_value integer[])
RETURNS integer[]
LANGUAGE plpgsql
IMMUTABLE
AS $function$
DECLARE res integer[];
BEGIN
select array_agg(coalesce(a,x'FFFFFFFF'::integer) & coalesce(b,x'FFFFFFFF'::integer)) as s
into res
from unnest(agg_state, cur_value) x(a,b);
return res;
END;
$function$
;
CREATE OR REPLACE AGGREGATE bit_array_and(integer[]) (
SFUNC = bit_mask_and_state,
STYPE = integer[]
);
CREATE OR REPLACE FUNCTION bit_mask_or_state(agg_state integer[], cur_value integer[])
RETURNS integer[]
LANGUAGE plpgsql
IMMUTABLE
AS $function$
DECLARE res integer[];
BEGIN
select array_agg(coalesce(a,0) | coalesce(b,0)) as s
into res
from unnest(agg_state, cur_value) x(a,b);
return res;
END;
$function$
;
CREATE OR REPLACE AGGREGATE bit_array_or(integer[]) (
SFUNC = bit_mask_or_state,
STYPE = integer[]
);
Tried to create aggregate like this
CREATE AGGREGATE my_sum(integer[]) (
SFUNC = bit_mask_or_state,
STYPE = integer[],
COMBINEFUNC = bit_mask_or_state,
PARALLEL = SAFE
);
But it didn't work as I expected. Ended up with the following
select bit_mask_and_state(
bit_array_or(r.mask_array) FILTER (WHERE r."type" = 1),
bit_array_or(r.mask_array) FILTER (WHERE r."type" = 2)
)
from ... r
PARALLEL SAFE." Did you actually test this on a table where the query planner did consider it advantageous to use multiple workers?