231

I am using PostgreSQL via the Ruby gem 'sequel'.

I'm trying to round to two decimal places.

Here's my code:

SELECT ROUND(AVG(some_column),2)    
FROM table

I get the following error:

PG::Error: ERROR:  function round(double precision, integer) does 
not exist (Sequel::DatabaseError)

I get no error when I run the following code:

SELECT ROUND(AVG(some_column))
FROM table

Does anyone know what I am doing wrong?

the Tin Man
  • 150,910
  • 39
  • 198
  • 279
user1626730
  • 2,843
  • 5
  • 17
  • 24
  • 3
    Your error message doesn't match the code in your question. – mu is too short Oct 28 '12 at 21:39
  • The syntax error aside, this [closely related question on dba.SE](http://dba.stackexchange.com/q/21036/3684) sheds some light on rounding double precision numbers in PostgreSQL. – Erwin Brandstetter Oct 28 '12 at 23:16
  • @muistooshort, Thanks for pointing that out. It should say 'round' where it says 'avg'. Edited. – user1626730 Oct 28 '12 at 23:31
  • for searching results sake, I also get this hint as output from the prompt: `HINT: No function matches the given name and argument types. You might need to add explicit type casts.` – Vzzarr Apr 21 '20 at 10:32

8 Answers8

327

PostgreSQL does not define round(double precision, integer). For reasons @Mike Sherrill 'Cat Recall' explains in the comments, the version of round that takes a precision is only available for numeric.

regress=> SELECT round( float8 '3.1415927', 2 );
ERROR:  function round(double precision, integer) does not exist

regress=> \df *round*
                           List of functions
   Schema   |  Name  | Result data type | Argument data types |  Type  
------------+--------+------------------+---------------------+--------
 pg_catalog | dround | double precision | double precision    | normal
 pg_catalog | round  | double precision | double precision    | normal
 pg_catalog | round  | numeric          | numeric             | normal
 pg_catalog | round  | numeric          | numeric, integer    | normal
(4 rows)

regress=> SELECT round( CAST(float8 '3.1415927' as numeric), 2);
 round 
-------
  3.14
(1 row)

(In the above, note that float8 is just a shorthand alias for double precision. You can see that PostgreSQL is expanding it in the output).

You must cast the value to be rounded to numeric to use the two-argument form of round. Just append ::numeric for the shorthand cast, like round(val::numeric,2).


If you're formatting for display to the user, don't use round. Use to_char (see: data type formatting functions in the manual), which lets you specify a format and gives you a text result that isn't affected by whatever weirdness your client language might do with numeric values. For example:

regress=> SELECT to_char(float8 '3.1415927', 'FM999999999.00');
    to_char    
---------------
 3.14
(1 row)

to_char will round numbers for you as part of formatting. The FM prefix tells to_char that you don't want any padding with leading spaces.

stenci
  • 7,245
  • 11
  • 54
  • 89
Craig Ringer
  • 259,831
  • 56
  • 584
  • 684
  • Hmm. When I try out `ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);`, I get '0.314E1'. And I have my code written as `ROUND(AVG(val),2)` yet still get the error I described in my question. – user1626730 Oct 28 '12 at 23:26
  • I just ran `ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);` on PgAdmin and Ruby. With PgAdmin, I get 3.14, but with Ruby (using he Sequel gem) I get '0.314E1'. I wonder why this is... – user1626730 Oct 28 '12 at 23:36
  • 14
    *"For some odd reason the version of round that takes a precision is only available for numeric."* Floating-point numbers are "useful approximations". If you ask code to round a floating-point number to two decimal places, returning *another* floating-point number, there's no guarantee that the closest approximation to the "right" answer will have only two digits to the right of the decimal. Numerics are effectively scaled integers; they don't have that problem. – Mike Sherrill 'Cat Recall' Oct 29 '12 at 00:27
  • @Catcall Good point - a `double` version of `round` would need to return `numeric` or (ugh) `text`, so it might as well take a `numeric` argument. – Craig Ringer Oct 29 '12 at 00:29
  • @user1626730 Ruby, or Ruby's `pg` gem, must do weird things with `numeric` values. Are you formatting it for display to the user? If so, see updated answer. – Craig Ringer Oct 29 '12 at 00:32
  • @user1626730 If you're still seeing an error after casting to numeric, please show your real code. – Craig Ringer Oct 29 '12 at 00:38
  • @CraigRinger It does seem that the gem does weird things. However, your TO_CHAR code worked. The result has blank spaces at the beginning of it, but I can strip those off with Ruby. – user1626730 Oct 29 '12 at 17:11
  • @user1626730 As per the documentation, if you don't want the padding for the sign use the `FM` version, eg `SELECT to_char(float8 '3.1415927', 'FM999999999.00')`. Answer amended. – Craig Ringer Oct 29 '12 at 23:38
  • 6
    For those trying to find the comment by @Catcall : now it is _Mike Sherrill 'Cat Recall'_ – 18446744073709551615 Apr 07 '16 at 07:35
105

Try also the old syntax for casting,

SELECT ROUND(AVG(some_column)::numeric,2)    
FROM table;

works with any version of PostgreSQL.

There are a lack of overloads in some PostgreSQL functions, why (???): I think "it is a lack" (!), but @CraigRinger, @Catcall and the PostgreSQL team agree about "pg's historic rationale".

PS: another point about rounding is accuracy, check @IanKenney's answer.


Overloading as casting strategy

You can overload the ROUND function with,

 CREATE FUNCTION ROUND(float,int) RETURNS NUMERIC AS $$
    SELECT ROUND($1::numeric,$2);
 $$ language SQL IMMUTABLE;

Now your instruction will works fine, try (after function creation)

 SELECT round(1/3.,4); -- 0.3333 numeric

but it returns a NUMERIC type... To preserve the first commom-usage overload, we can return a FLOAT type when a TEXT parameter is offered,

 CREATE FUNCTION ROUND(float, text, int DEFAULT 0) 
 RETURNS FLOAT AS $$
    SELECT CASE WHEN $2='dec'
                THEN ROUND($1::numeric,$3)::float
                -- ... WHEN $2='hex' THEN ... WHEN $2='bin' THEN... complete!
                ELSE 'NaN'::float  -- like an error message 
            END;
 $$ language SQL IMMUTABLE;

Try

 SELECT round(1/3.,'dec',4);   -- 0.3333 float!
 SELECT round(2.8+1/3.,'dec',1); -- 3.1 float!
 SELECT round(2.8+1/3.,'dec'::text); -- need to cast string? pg bug 

PS: checking \df round after overloadings, will show something like,

 Schema     |  Name | Result data type | Argument data types 
------------+-------+------------------+----------------------------
 myschema   | round | double precision | double precision, text, int
 myschema   | round | numeric          | double precision, int
 pg_catalog | round | double precision | double precision            
 pg_catalog | round | numeric          | numeric   
 pg_catalog | round | numeric          | numeric, int          

The pg_catalog functions are the default ones, see manual of build-in math functions.

Community
  • 1
  • 1
Peter Krauss
  • 11,340
  • 17
  • 129
  • 247
43

Try with this:

SELECT to_char (2/3::float, 'FM999999990.00');
-- RESULT: 0.67

Or simply:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67
atiruz
  • 2,461
  • 22
  • 34
10

you can use the function below

 SELECT TRUNC(14.568,2);

the result will show :

14.56

you can also cast your variable to the desire type :

 SELECT TRUNC(YOUR_VAR::numeric,2)
AdagioDev
  • 347
  • 3
  • 11
6

Try casting your column to a numeric like:

SELECT ROUND(cast(some_column as numeric),2) FROM table
4

According to Bryan's response you can do this to limit decimals in a query. I convert from km/h to m/s and display it in dygraphs but when I did it in dygraphs it looked weird. Looks fine when doing the calculation in the query instead. This is on postgresql 9.5.1.

select date,(wind_speed/3.6)::numeric(7,1) from readings;
kometen
  • 4,305
  • 3
  • 36
  • 39
2
SELECT ROUND(SUM(amount)::numeric, 2) AS total_amount
FROM transactions

Gives: 200234.08

heilala
  • 532
  • 5
  • 16
vlatko606
  • 481
  • 4
  • 12
1

Error:function round(double precision, integer) does not exist

Solution: You need to addtype cast then it will work

Ex: round(extract(second from job_end_time_t)::integer,0)

huzeyfe
  • 2,846
  • 5
  • 33
  • 46