Postgres real rounds to 4 decimal places - postgresql

I have a column latitude of type real in my Postgres table.
Looking at it in Postico, it has the value of 57.70887.
But selecting it from psql or via code, the value returned is rounded to 4 decimal places:
# SELECT latitude from categories where id = 4;
latitude
----------
57.7089
(1 row)
What am I doing wrong?
Postgres 9.6.

The column should not be real if you care for precision. Floating point types only store approximate values. Use numeric instead to preserve the value exactly as inserted.
Consider:
Value of real type incorrectly compares
How to round REAL type to NUMERIC?
Can the Postgres data type NUMERIC store signed values?

Related

Rails: Storing high currency values in PostgreSQL

I would like to store high value currency values into the DB.
I tried to use an integer field in my migration, however I get following error
PG::NumericValueOutOfRange: ERROR: numeric field overflow
DETAIL: A field with precision 8, scale 2 must round to an absolute value less than 10^6.
So I then tried to use decimal with precision
t.decimal :value, precision: 30, scale: 2
Once gain I am getting the same error when I enter
What I would like to know, is it possible, and how can I save a value like 1000000.0 into the database.
I tried to use an integer field in my migration, however I get following error
PG::NumericValueOutOfRange: ERROR: numeric field overflow
DETAIL: A field with precision 8, scale 2 must round to an absolute value less than 10^6.
That's a misunderstanding. The error message is for data type numeric - numeric(8,2) to be precise - not integer.
Solution
Just use numeric without precision and scale. It stores decimal number (with any amount of fractional digits) exactly as given.
decimal is a synonym of numeric in Postgres.
If you don't have fractional digits, consider integer (max 2^31 - 1) or bigint (max 2^63 - 1).
Related:
PostgreSQL: Which Datatype should be used for Currency?

Postgres Custom float type that is always truncated to 2 decimals after point

Can I generate a custom data type in postgres that everytime I insert or update a float into it it is truncate to 2 decimals after dot.
create table money(
formatted moneys_type
);
insert into money values (30.122323213);
Select * from money;
Returns
30.12
Update I didn't use numeric or decimal because they round up when 1.999 => 2
See documentation on Numeric Types / Arbitrary Precision Numbers.
The precision of a numeric is the total count of significant digits in
the whole number, that is, the number of digits to both sides of the
decimal point. The scale of a numeric is the count of decimal digits
in the fractional part, to the right of the decimal point. So the
number 23.5141 has a precision of 6 and a scale of 4. Integers can be
considered to have a scale of zero.
...
To declare a column of type numeric use the syntax:
NUMERIC(precision, scale)
The maximum allowed precision when explicitly specified in the type declaration is 1000.
So you can use
NUMERIC(1000, 2)

Can the Postgres data type NUMERIC store signed values?

In PostgreSQL, I would like to store signed values -999.9 - 9999.9.
Can I use numeric(5.1) for this?
Or what type should I use?
You can certainly use the arbitrary precision type numeric with a precision of 5 and a scale of 1, just like #Simon commented, but without the syntax error. Use a comma(,) instead of the dot (.) in the type modifier:
SELECT numeric(5,1) '-999.9' AS nr_lower
, numeric(5,1) '9999.9' AS nr_upper;
nr_lower | nr_upper
----------+----------
-999.9 | 9999.9
The minus sign and the dot in the string literal do not count against the allowed maximum of significant digits (precision).
If you don't need to restrict the length, just use numeric.
If you need to enforce minimum and maximum, add a check constraint:
CHECK (nr_column BETWEEN -999.9 AND 9999.9)
numeric stores your number exactly. If you don't need the absolute precision and tiny rounding errors are no problem, you might also use one of the floating point types double precision (float8) or real (float4).
Or, since you only allow a single fractional decimal digit, you can multiply by 10 and use integer, which would be the most efficient storage: 4 bytes, no rounding errors and fastest processing. Just use and document the number properly.
Details for numeric types in the manual.

How to set precision and scale in ALTER TABLE

I have working code with PostgreSQL 9.3:
ALTER TABLE meter_data ALTER COLUMN w3pht TYPE float USING (w3pht::float);
but don't know how to set precision and scale.
The type float does not have precision and scale. Use numeric(precision, scale) instead if you need that.
Per documentation:
The data types real and double precision are inexact, variable-precision numeric types.
For your given example:
ALTER TABLE meter_data ALTER COLUMN w3pht TYPE numeric(15,2)
USING w3pht::numeric(15,2) -- may or may not be required
The manual:
A USING clause must be provided if there is no implicit or assignment cast from old to new type.
Example: if the old data type is text, you need the USING clause. If it's float, you don't.
As per PostgreSQL documentation, you can select the minimum number for the floating point numbers using syntax float(n) where n is the minimum number of binary digits, up to 53.
However, to store decimal values at all, use numeric(precision, scale) or its synonym decimal(precision, scale) but notice that these are hard limits; according to the documentation:
If the scale of a value to be stored is greater than the declared
scale of the column, the system will round the value to the specified
number of fractional digits. Then, if the number of digits to the left
of the decimal point exceeds the declared precision minus the declared
scale, an error is raised.
Thus your alter table could be:
ALTER TABLE meter_data
ALTER COLUMN w3pht TYPE numeric(10, 2)
USING (w3pht::numeric(10, 2));
for 2 digits right of decimal point and 10 total digits. However if you do not
need to specify limits, simple numeric will allow "up to 131072 digits before the decimal point; up to 16383 digits after".

Getting float values out of PostgreSQL

I am having trouble retrieving float/real values out of PostgreSQL.
For example, I would like to store: 123456789123456, the retrieve that exact same number with a select statement.
table tbl (num real)
insert into tbl(num) values('123456789123456');
As it is now, if I "select num from tbl" the result is "1.23457e+14"
If I run "select CAST(num AS numeric) as num from tbl" the result is 123457000000000
If I run "select CAST(num AS float) as num from tbl" the result is 123456788103168 (where did this number come from)
How on earth can I select the value and get "123456789123456" as the result?
Thanks so much in advance
You declared the table with the column having a type of "real", which is a fairly low-precision floating-point number.
You probably want to use the type "double precision" (aka "float" or "float8") for a reasonable degree of floating-point accuracy. If you know the magnitude and precision of numbers you need to store, you may be better off declaring the column type as numeric(PREC,SCALE) instead - PREC being the total number of digits to keep, and SCALE the number of digits that will be to the right of the decimal point.
The real type has only 6 decimal digits of precision, so it can't store your number exactly. You may need to use "double precision" or "numeric/decimal" type.
Source: http://www.postgresql.org/docs/8.4/static/datatype-numeric.html .