We have found an anomaly using the ROUND function. While developing, when we made a certain calculation in a SELECT we got the right results. If we later wrote the UPDATE statement, using that very same calculation, we found different results written in the table:
We were making calculations based on the number of days 1 or more persons did a certain activity. We divided those days by the number of days in that year to determine “yearly” activity: less than half the days present in a year = 0, equal or more than half the days in a year = 1, .... For certain numbers of days of activity, we found 0 written in the table, when it should have been 1.
SQL-instructions needed to reproduce the bug:
Code:
-- make a function to generate a test data set
-- kudos to Greame Birchall's DB2 Cookbook
create function NumList(max_num INTEGER)
RETURNS TABLE (num Integer)
LANGUAGE SQL
RETURN
WITH temp1 (num) AS
(VALUES (0)
UNION ALL
SELECT num + 1
FROM temp1
WHERE num < max_num
)
SELECT num
FROM temp1
;
-- create a test table
drop table test;
CREATE TABLE test (
num INTEGER NOT NULL,
res_365 DEC(7) NOT NULL,
res_365_DEC DEC(7) NOT NULL,
res_366 DEC(7) NOT NULL,
res_366_DEC DEC(7) NOT NULL,
constraint pk_test primary key (num)
);
Code:
-- populate the test table with a sequence from 0 to 500
DELETE FROM test;
INSERT INTO test
SELECT T.num,
ROUND(T.num / double(365), 0),
CAST(ROUND(T.num / double(365), 0) as DEC(7)),
ROUND(T.num / double(366), 0),
CAST(ROUND(T.num / double(366), 0) as DEC(7))
from TABLE(NumList(500)) as T
;
-- Compare the data in the table with at runtime calculated values.
-- The "round(T.num / double(365), 0)" generates the correct results,
-- the field "res_365" that was filled using that very same calculation
-- differs from time to time.
-- Because the result is written in a DEC(7) field, I did an explicit CAST
-- to a DECIMAL(7) (the XX_DEC fields) but even then the values differ.
-- They start do differ (from time to time) from num = 186 until num =
-- (days of year – 1).
select T.num,
res_365,
res_365_DEC,
round(T.num / double(365), 0) as "365",
res_366,
res_366_DEC,
round(T.num / double(366), 0) as "366"
from test as T
order by 1
;
You can run this code to see if your system is affected too. I'd love to hear from the DB2 V9.x guys if this flaw is also present in that version.
P.S. I have reported this to IBM.