问题
I try to create an aggregate for product (*) in PostgreSQL. The field type of my row is "double precision"
So, I tried :
CREATE AGGREGATE nmul(numeric)
(
sfunc = numeric_mul,
stype = numeric
);
When I launch my query, the result :
ERROR: function nmul(double precision) does not exist
LINE 4: CAST(nmul("cote") AS INT),
Thank you
回答1:
I found a solution from a very smart guy, who realized you can use logarithms to achieve this (credit goes to him):
select exp(sum(ln(x))) from generate_series(1,5) x;
exp
-----
120
(1 row)
回答2:
Cast your input from double precision
(float8
) to numeric
, or define a double precision
flavour of your aggregate.
Your aggregate works fine:
regress=> CREATE AGGREGATE nmul(numeric)
regress-> (
regress(> sfunc = numeric_mul,
regress(> stype = numeric
regress(> );
regress=> SELECT nmul(x) FROM generate_series(1,100) x;
nmul
----------------------------------------------------------------------------------------------------------------------------------------------------------------
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
(1 row)
the issue is your query:
regress=> SELECT nmul(x::float8) FROM generate_series(1,100) x;
ERROR: function nmul(double precision) does not exist
LINE 1: SELECT nmul(x::float8) FROM generate_series(1,100) x;
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
You can define a float8
version of your aggregate (float8
is a synonym for double precision
):
regress=> CREATE AGGREGATE nmul(double precision)
(
sfunc = float8mul,
stype = float8
);
regress=> SELECT nmul(x::float8) FROM generate_series(1,100) x;
fmul
-----------------------
9.33262154439441e+157
(1 row)
or cast to numeric
before aggregation if you want to retain the full precision of the value, eg:
CAST(nmul(CAST("cote" AS numeric)) AS INT)
or the PostgreSQL-specific shorthand cast:
nmul("cote"::numeric)::integer
Note that integer
will overflow very quickly when you're working with these product aggregates:
regress=> SELECT nmul(x)::integer FROM generate_series(1,12) x;
nmul
-----------
479001600
(1 row)
regress=> SELECT nmul(x)::integer FROM generate_series(1,13) x;
ERROR: integer out of range
regress=>
so you're likely to want to stick with numeric
anyway.
来源:https://stackoverflow.com/questions/13156055/product-aggregate-in-postgresql