Redshift error Overflow for NUMERIC(8,4) - amazon-redshift

Why do I get "Overflow for NUMERIC(8,4)" for 10595.148?

Redshift is based on PostgreSQL, so it follows the PostgreSQL rules for numeric data types.
NUMERIC(8,4) indicates a scale of 4, so it will try to store your number with 4 decimal digits in the fraction part: 10595.1480. This number has 9 digits, which is higher than the precision of 8. The maximum number you can store in this data type is 9999.9999.

Related

Storing values as real data type in PostgreSQL. Confusion about the concept of precision

I am confused about the real data type in PostgreSQL:
CREATE TABLE number_data_types (
numeric_column numeric(20,5),
real_column real,
double_column double precision
);
INSERT INTO number_data_types
VALUES (.7, .7, .7),
(2.13579, 2.13579, 2.13579),
(2.1357987654, 2.1357987654, 2.1357987654)
);
SELECT * FROM number_data_types;
The output in the 3rd row, 2nd column is 2.1357987. Since the real data type in PostgreSQL has a precision of 6, the number of digits in a number that can be stored is 6. I expected to see the number 2.13579, because there are 6 digits in the number. What's wrong with my thought?
In my textbook, the author writes: "On the third row, you see PostgreSQL's default behavior in those two columns, which is to output floating-point numbers using their shortest precise decimal representation rather than show the entire value."
The precision on a real is at least 6 digits. From the docs...
On all currently supported platforms, the real type has a range of around 1E-37 to 1E+37 with a precision of at least 6 decimal digits.
When displayed a real (aka float4) can display up to 9 digits.
By default, floating point values are output in text form in their shortest precise decimal representation; the decimal value produced is closer to the true stored binary value than to any other value representable in the same binary precision. (However, the output value is currently never exactly midway between two representable values, in order to avoid a widespread bug where input routines do not properly respect the round-to-nearest-even rule.) This value will use at most 17 significant decimal digits for float8 values, and at most 9 digits for float4 values.
Floating point numbers try to cram a lot of precision into a very small space. As a result they have a lot of quirks.

Source qualifier allowing value more than defined size in Informatica

One of my informatica session behaving weird. For a particular column precision and scale values are defined as 17,16respectively and enable the high precision is on.
As per the precision and scale values it should allow the numbers which are having only single digit before the decimal point but in my session it allowing upto 2digits before the decimal point and failing for 3digits before the decimal point with the error Invalid number
. I am confused why it's allowing 2digits numbers as it should fail for them too?
Ex: precision 17,scale 16
1.4567--allowed
12.4567--allowed
123.4567-- rejected
In addition to it I observed that in the source that column has data type as number but coming to source qualifier same column has data type decimal. Why this internal convertion happened?
Can anyone help on this?
As for the second part of the question: one of Source Qualifier transformation fuctions is to convert any Source data types to PowerCenter data types. Whatever source you will use, Source Qualifier will convert the data types. This way you end up with same data types and comparison between Orace and MS SQL Server won't be a problem.
This is whats happening in case of '12.4567 -- allowed'. Since you have high precision mode on, infa is converting decimal to double automatically. Double is 8byte data. So, if you set something
col(11,9) and trying to insert 1234567890.1, infa will fail.
Summary -
If you specify the precision greater than the maximum number of digits, the Data Integration Service converts decimal values to double in high precision mode.
This is as per Infa documentation
8 bytes (if high precision is off or precision is greater than 38)
16 bytes (if precision <= 18 and high precision is on)
20 bytes (if precision > 18 and <= 28)
24 bytes (if precision > 28 and <= 38)
Decimal value with declared precision and scale. Scale must be less than or equal to precision.
For transformations that support precision up to 38 digits, the precision is 1 to 38 digits, and the scale is 0 to 38.
For transformations that support precision up to 28 digits, the precision is 1 to 28 digits, and the scale is 0 to 28.
If you specify the precision greater than the maximum number of digits, the Data Integration Service converts decimal values to double in high precision mode.
https://docs.informatica.com/data-integration/powercenter/10-2/developer-tool-guide/data-type-reference/transformation-data-types.html

How to automatically use appropriate precision/scale for numeric type in postgres?

I have a numeric type in postgres with a value of 1.9999999999999999 (scale is 16) and I run a query that calculates (1.9999999999999999+2)/2. The exact answer should be 1.99999999999999995 (scale should be 17) but instead I get 2.0000000000000000 (scale is still 16 again) because the default precision/scale of numeric is exceeded.
I could get around this by running the query and doing (1.9999999999999999+2)/2::numeric(1000,999), but then when I retrieve this value that was saved to the database, it actually appears with 1000 "0" digits in the SELECT query output.
How can I do either of the following?
Tell postgres never to round a value if it exceeds the scale, but increase the scale automatically instead
Tell postgres not to store trailing "0" digits after the decimal, and keep only the minimum number of digits it needs, so that I can use the highest possible scale ::numeric(1000,999) but it only stores the necessary digits?
I'd like to get exact results for any operations I do on numeric values to the fullest precision that postgres allows, but not store unnecessary trailing "0" digits. Like how you would expect it to work if you were calculating it manually.

Performance of NUMERIC type with high precisions and scales in PostgreSQL

I am storing cryptocurrency transaction balances in NUMERIC column. As cryptocurrency values vary in somewhat extreme ranges compared to traditional currency, I am using NUMERIC(60,20) type to capture all uses cases. As this feel little bit extreme, I am curious
What are the performance (CPU) penalties of increasing NUMERIC column precision and scale
What are the storage cost penalties of increasing NUMERIC column precision and scale
The declared scale and precision of a NUMERIC column serve as a constraint on your inserted values, but they do not directly affect storage requirements; 1::NUMERIC(1,0), 1::NUMERIC(99,98) and 1::NUMERIC all have identical underlying representations. With this in mind, your best option might be to use an unconstrained NUMERIC column, and cast your values to a suitable scale/precision on a currency-by-currency basis.
NUMERIC values are stored as variable-length arrays of base-10,000 digits, each represented by a 16-bit integer, so the storage cost is 2 bytes per 4 decimal digits, plus a 6-byte header for each value. The fractional and integer portions are stored separately, so 11 consumes 8 bytes, while 1.1 requires 10. You can check the storage requirements for a given value using e.g. SELECT pg_column_size(1.1::NUMERIC).
As for the CPU overhead, I would expect that the cost of most operations scales linearly with the number of digits. However, this is generally dwarfed by the I/O cost of fetching the value in the first place, so it's likely a non-issue. You'd have to try your queries on your own hardware to know for sure.

Does PostgreSQL support rounding at the database level?

For example is it possible to ensure that a particular number field is always rounded to exactly three decimal places?
Yes. Define the column as DECIMAL(16, 3) - see the postgres documentation for this type
The first number (16 in this case) is the maximum total number of digits in the number, the second number (3 in this case) is the number of decimal places.
Every database (I know of) supports this datatype.