Search code examples
oracle-databasenumbersrounding-error

How does ORACLE DB sum NUMBER(*,s) with many records?


I am wondering how Oracle sums NUMBER(9,2) with SUM(numWithScale/7).

This is because I am wondering how the error will propagate with a large amount of records

Let's say I have a table EMP_SAL with some EMP_ID, numWithScale, numWithScale being a salary.

To make it simple, let us make the numWithScale column NUMBER(9,2) 9 decimals of precision with 2 decimals to round to. All of these numbers in the table are random digits from 10.00-20.00 (ex. 10.12, 20.00, 19.95)

I divide by 7 in my calculation to give random digits at the end that round up or down.

Now, I sum all of the employees salaries with SUM(numWithScale/7).

Will the sum round each time it adds a record? Or does Oracle round after the calculation is complete? i.e. the error can be +/-0.01 from rounding, and with many additions then roundings, error adds up. Or does it round at the end? Thus I dont have to worry about the error adding up (unless I use the result in many more calculations)

Also, will Oracle return the sum as the more precise NUMBER, (38 digit precision, floating point)? or will it round up to the second digit NUMBER(9,2) when returning the value?

Will MSSQL behave pretty much the same way (even though syntax is different?


Solution

  • Oracle performs operation in the order you specified.

    So, if you write this query:

    select SUM(numWithScale/7) from some_table -- (1)
    

    each of values divided by 7 and rounded to maximum available precision: NUMBER with 38 significant digits. After that all digits are summed.

    In case of this query:

    select SUM(numWithScale)/7 from some_table -- (2)
    

    all numWithScale values are summed and only after that divided by 7. In this case there are no precision loss for each record, only result of sum() division by 7 are rounded to 38 significant digits.

    This problem are common for calculation algorithms. Each time when you divide value by 7 you produce small calculation error because of limited number of digits, representing a number:
    numWithScale/7 => quotient + delta.
    While summing this values you got
    sum(quotient) + sum(delta).

    If numWithScale represents ideal uniform distribution and and a some_table contains infinite number of records, then sum(delta) tends to zero. But it happens only in theory. In practical cases sum(delta) grows and introduces significant error. This is a case of query(1).

    On the other hand, summing can't introduce a rounding error if implemented properly. So for query (2) rounding error introduced only in last step, when whole sum divided by 7. Therefore value of delta for this query not affected by number of records.