Product Aggregate in PostgreSQL

淺唱寂寞╮ 提交于 2019-12-23 12:27:19

问题


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

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