PostgreSQL Arbitrary Precision Numbers Explained
This post is part of a series on the numeric data types found in PostgreSQL. Read on to learn all about defining arbitrary precision numbers in PostgreSQL. Write a comment if you have any questions or corrections!
Arbitrary Precision Numbers
Name | Storage size | Range |
---|---|---|
numeric | variable | up to 131,072 digits before the decimal; up to 16,383 digits after the decimal |
decimal | variable | same as numeric |
Use numeric
or decimal
(they are interchangeable) to store monetary amounts and other quantities where exactness is required. Calculations on numeric
or decimal
values are slower than those performed on integer
and floating-point
types, but yield more exact results.
When defining a numeric
or decimal
type, you need to specify the amount of precision and scale that you want.
- Precision is the total count of digits on both sides of the decimal. For example, a number like
237.56
has a precision of 5.130023.303
has a precision of 9. The precision must be positive. - Scale is count of decimal digits (i.e. the amount of digits to the right of the decimal). For example,
921.240
has a scale of 3.3490.12
has a scale of 2. Integers have a scale of zero. The scale must be zero or positive.
When defining a numeric
or decimal
column type the syntax is:
NUMERIC(precision, scale);
DECIMAL(precision, scale);
Examples:
NUMERIC(5, 2) -- Stores numbers up to 999.99
Let's imagine I've created a table called num_tests
and I have one column called numbah
with a data type of NUMERIC(5, 2)
. This means that numbah
will have a precision of 5 and a scale of 2. It will store numbers up to 999.99.
Now let's explore what happens when we try to store different values into this column.
-- Table definition
CREATE TABLE num_tests (
numbah NUMERIC(5, 2)
);
/*
Stores 2.32 as that number is in
the precision and scale range defined.
*/
INSERT INTO num_tests VALUES(2.32);
/*
Stores 3.40. Rounds any digits that
come after the scale defined. Since our
scale is 2, but we're inserting .402
that gets rounded to .40
*/
INSERT INTO num_tests VALUES(3.402);
/*
Stores 3.00. Adds the two zeros to satisfy
our scale condition of 2.
*/
INSERT INTO num_tests VALUES(3);
/*
Errors out with error: numeric field overflow
This happens because the number is greater
than the precision specified.
*/
INSERT INTO num_tests VALUES(3023.23);
Alternatively, we can define the numeric
or decimal
type by leaving off the scale or the precision AND scale.
DECIMAL(precision);
DECIMAL;
With no scale defined, the scale defaults to zero. When you don't specify any precision or scale, this creates a column where any precision and scale can be stored, up to the range as defined in the table above. Best practice seems to be to always define your precision and scale.
The maximum allowed precision when explicitly defined as a type (NUMERIC(5, 2)
) is 1000.
Besides numeric values, you can also store NaN
("not-a-number") values in the numeric
or decimal
type.
INSERT INTO num_tests VALUES('NaN');
When PostgreSQL rounds a numeric
or decimal
value like -2.5
it will round up to -3
. This behaves slightly differently from real
and double precision
rounding, which rounds to the nearest even number. For example:
x | numeric | double
------+-----------+-----------
-3.5 | -4 | -4
-2.5 | -3 | -2
-1.5 | -2 | -2
-0.5 | -1 | -0
0.5 | 1 | 0
1.5 | 2 | 2
2.5 | 3 | 2
3.5 | 4 | 4
More Numeric Types
Learn about the other numeric data types in one of the following posts:
What to see more of this kind of content? Let me know in the comments or reach out on Twitter!