Pass extra parameter to PostgreSQL aggregate final function

北慕城南 提交于 2019-12-31 02:23:11

问题


Is the only way to pass an extra parameter to the final function of a PostgreSQL aggregate to create a special TYPE for the state value?

e.g.:

CREATE TYPE geomvaltext AS (
    geom public.geometry,
    val double precision,
    txt text
);

And then to use this type as the state variable so that the third parameter (text) finally reaches the final function?

Why aggregates can't pass extra parameters to the final function themselves? Any implementation reason?

So we could easily construct, for example, aggregates taking a method:

SELECT ST_MyAgg(accum_number, 'COMPUTE_METHOD') FROM blablabla

Thanks


回答1:


You can define an aggregate with more than one parameter.

I don't know if that solves your problem, but you could use it like this:

CREATE OR REPLACE FUNCTION myaggsfunc(integer, integer, text) RETURNS integer
   IMMUTABLE STRICT LANGUAGE sql AS
$f$
   SELECT CASE $3
           WHEN '+' THEN $1 + $2
           WHEN '*' THEN $1 * $2
           ELSE NULL
        END
$f$;

CREATE AGGREGATE myagg(integer, text) (
   SFUNC = myaggsfunc(integer, integer, text),
   STYPE = integer
);

It could be used like this:

CREATE TABLE mytab
   AS SELECT * FROM generate_series(1, 10) i;

SELECT myagg(i, '+') FROM mytab;

 myagg 
-------
    55
(1 row)

SELECT myagg(i, '*') FROM mytab;

  myagg  
---------
 3628800
(1 row)



回答2:


I solved a similar issue by making a custom aggregate function that did all the operations at once and stored their states in an array.

CREATE AGGREGATE myagg(integer)
(
    INITCOND = '{ 0, 1 }',
    STYPE = integer[],
    SFUNC = myaggsfunc
);

and:

CREATE OR REPLACE FUNCTION myaggsfunc(agg_state integer[], agg_next integer)
RETURNS integer[] IMMUTABLE STRICT LANGUAGE 'plpgsql' AS $$
BEGIN
    agg_state[1] := agg_state[1] + agg_next;
    agg_state[2] := agg_state[2] * agg_next;
    RETURN agg_state;
END;
$$;

Then made another function that selected one of the results based on the second argument:

CREATE OR REPLACE FUNCTION myagg_pick(agg_state integer[], agg_fn character varying)
RETURNS integer IMMUTABLE STRICT LANGUAGE 'plpgsql' AS $$
BEGIN
    CASE agg_fn
        WHEN '+' THEN RETURN agg_state[1];
        WHEN '*' THEN RETURN agg_state[2];
        ELSE RETURN 0;
    END CASE;
END;
$$;

Usage:

SELECT myagg_pick(myagg("accum_number"), 'COMPUTE_METHOD') FROM "mytable" GROUP BY ...

Obvious downside of this is the overhead of performing all the functions instead of just one. However when dealing with simple operations such as adding, multiplying etc. it should be acceptable in most cases.




回答3:


You would have to rewrite the final function itself, and in that case you might as well write a set of new aggregate functions, one for each possible COMPUTE_METHOD. If the COMPUTE_METHOD is a data value or implied by a data value, then a CASE statement can be used to select the appropriate aggregate method. Alternatively, you may want to create a custom composite type with fields for accum_number and COMPUTE_METHOD, and write a single new aggregate function that uses this new data type.



来源:https://stackoverflow.com/questions/46411209/pass-extra-parameter-to-postgresql-aggregate-final-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!