This article shows you a possible solution to handle rounding issues in Teradata.
Let’s assume we have the following table definition:
CREATE VOLATILE TABLE ROUNDING_PROBLEM
(
AMOUNT DECIMAl(18,2),
MONTHS INTEGER
) NO PRIMARY INDEX ON COMMIT PRESERVE ROWS;
INSERT INTO ROUNDING_PROBLEM VALUES (10.25,3);
Let’s further assume that our task is to divide each amount by the number of months; this means per record, you have to do the following calculation:
AMOUNT / MONTHS
This is not challenging from an implementation point of view but leads to Teradata rounding problems:
SELECT The_Month,SUM(val)
FROM
(
SELECT 1 as the_month ,AMOUNT/MONTHS AS val FROM ROUNDING_PROBLEM
UNION ALL
SELECT 2 the_month ,AMOUNT/MONTHS as val FROM ROUNDING_PROBLEM
UNION ALL
SELECT 3 the_month ,AMOUNT/MONTHS as val FROM ROUNDING_PROBLEM
) x
GROUP BY 1
ORDER BY 1
;
Unfortunately, you will end up with this result:
The_Month Sum(val)
1 3,42
2 3,42
3 3,42
10,26
As you can see, the result is 10,26, but the sum should be 10,25.
There is no easy solution as we only have two digits of the precision available in our table.
Still, there is a solution: create an additional record holding the rounding difference (in my example, I added it to the last month):
SELECT The_Month,SUM(val)
FROM
(
SELECT 1 as the_month ,AMOUNT/MONTHS AS val FROM ROUNDING_PROBLEM
UNION ALL
SELECT 2 the_month ,AMOUNT/MONTHS as val FROM ROUNDING_PROBLEM
UNION ALL
SELECT 3 the_month ,AMOUNT/MONTHS as val FROM ROUNDING_PROBLEM
UNION ALL
SELECT 3, AMOUNT – (AMOUNT/MONTHS*MONTHS) FROM ROUNDING_PROBLEM
) x
GROUP BY 1
ORDER BY 1
;
The_Month Sum(val)
1 3,42
2 3,42
3 3,41
10,25
Now we can add the monthly amounts and have the correct results in aggregations. On the other hand, we have an additional record that identifies the rounding differences. It could be stored with a particular identification code to distinguish it from the regular records.