Getting float values out of PostgreSQL - 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 .

Related

Why are 2 numeric values with many decimal places considered equal in postgres?

Why is select (1.9999999999999999+2)/2 = (1.9999999999999999999999999999999999+2)/2 equal to true in postgres? Doing select pg_typeof((1.9999999999999999999999999999999999+2)/2) shows type numeric, which the docs say are exact numbers are should support thousands of digits after the decimal.
select 1.9999999999999999 = 1.9999999999999999999999999999999999 returns false as expected.
Why does select (1.999999999999999+2)/2 show 1.9999999999999995 like I'd expect but adding an extra "9" to the end shows 2.0000000000000000? Shouldn't the extra digit increase the precision and I should see the extra "9" in the result too?
In what cases can I be sure I won't see this in my queries when doing arithmetic on numeric types?
The numeric expression on the left side has only 16 decimal digits. The overall expression evaluation is limited to that precision.
Try this:
select (1.9999999999999999000000000000000000+2)/2 = (1.9999999999999999999999999999999999+2)/2
And you'll get false because you are now comparing 34 decimals on both sides (if I counted right).

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)

Postgres real rounds to 4 decimal places

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?

Numeric overflow in insert query

I am receiving an error of:
Arithmetic overflow or division by zero has occurred. arithmetic
exception, numeric overflow, or string truncation. numeric value is
out of range.
This can be replicated with:
create table testing (avalue numeric(3,2));
and the following insert:
insert into testing values (328);
However, using the following works fine:
insert into testing values (327);
328 seems to be the magic figure the error occurs. To me, the numeric(3,2) declaration should allow me 000-999 with 2 decimal places but based on the above that is wrong.
Can someone explain why this is and what I should declare my domain as if I want to allow 0-999 with 2 decimal places as.
Thanks
328 is not "magic" number :)
The magic number is 32767 ( 0x7FFF). This is SMALLINT type limit.
Note : Firebird not support unsigned integer type.
Limit for NUMERIC type vary according to storage type and scale.
Internal storage type are SMALLINT, INTEGER and BIGINT according by precision as:
precision-type
1..4 - SMALLINT
5..9 - INTEGER
10..18 - BIGINT
So
NUMERIC(3,2) is SMALLINT internal type max 32767 / 100 = 327.67.
Update
Firebird 2.5 Language Reference
by
Paul Vinkenoog,
Dmitry Yemanov and
Thomas Woinke
contains more comprehensive description of NUMERIC type than other official Firebird documents.
NUMERIC (precision, scale) is the exact number with the decimal
precision and scale specified by the and .
Syntax:
NUMERIC [precision [, scale]]
The scale of NUMERIC is the count of decimal digits in the
fractional part, to the right of the decimal point. The precision of
NUMERIC is the total count of decimal digits in the number.
The precision must be positive, the maximum supported value is 18.
The scale must be zero or positive, up to the specified precision.
If the scale is omitted, then zero value is implied, thus
meaning an integer value of the specified precision, i.e.
NUMERIC (P) is equivalent to NUMERIC (P, 0). If both the precision and
the scale are omitted, then precision of 9 and zero scale are implied,
i.e. NUMERIC is equivalent to NUMERIC (9, 0).
The internal representation of the NUMERIC data type may vary.
Numerics with the precision up to (and including) 4 are always stored
as scaled short integers (SMALLINT). Numerics with the precision up to
(and including) 9 are always stored as scaled regular integers
(INTEGER). Storage of higher precision numerics depends on the SQL
dialect. In Dialect 3, they are stored as scaled large integers
(BIGINT). In Dialect 1, however, large integers are not available,
therefore they are stored as double precision floating-point values
(DOUBLE PRECISION).
The effective precision limit for the given value depends on the
corresponding storage. For example, NUMERIC (5) will be stored as
INTEGER, thus allowing values in the precision range up to (and
including) NUMERIC (9). So beware that the declared precision is not
strictly enforced.
Values outside the range limited by the effective precision are not
allowed. Values with the scale larger than the declared one will be
rounded to the declared scale while performing an assignment.
The declaration numeric(5, 2) gives you numbers from 0.00 to 999.99. The declaration numeric(3,2) gives you numbers from 0.00 to 9.99. This is sort-of illustrated here. But these are the standard declarations for numerics in SQL.
The "3" is the scale, which is the total number of digits in the number, not the number to the left of the decimal place.
I'm not sure why 327 is allowed.

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".