この記事は PostgreSQLのround()の話 に触発されて、Oracle Databaseでも同様の調査を行った結果です。
ROUND 関数による丸め
Oracle Database の ROUND 関数は他のデータベースと同様に数値を丸めるために使われます。しかし、データ型によって整数に丸めた場合の結果が変化します。NUMBER 型とBINARY_DOUBLE 型の列に値を格納して結果を確認します。
SQL> CREATE TABLE rd_table(c1 NUMBER(3, 1), c2 BINARY_DOUBLE);
Table created.
SQL> INSERT INTO rd_table VALUES (2.1, 2.1);
1 row created.
SQL> INSERT INTO rd_table VALUES (2.2, 2.2);
1 row created.
...
SQL> INSERT INTO rd_table VALUES (2.9, 2.9);
1 row created.
SQL> INSERT INTO rd_table VALUES (3.0, 3.0);
1 row created.
SQL> COMMIT
Commit complete.
整数値に変換するために、ROUND 関数を実行します。
SQL> SELECT c1, ROUND(c1), c2, ROUND(c2) FROM rd_table ORDER BY c1;
C1 ROUND(C1) C2 ROUND(C2)
---------- ---------- ---------- ----------
2.1 2 2.1E+000 2.0E+000
2.2 2 2.2E+000 2.0E+000
2.3 2 2.3E+000 2.0E+000
2.4 2 2.4E+000 2.0E+000
2.5 3 2.5E+000 2.0E+000
2.6 3 2.6E+000 3.0E+000
2.7 3 2.7E+000 3.0E+000
2.8 3 2.8E+000 3.0E+000
2.9 3 2.9E+000 3.0E+000
3 3 3.0E+000 3.0E+000
10 rows selected.
NUMBER 型の 2.5 に対して ROUND 関数を実行すると 3 になるのに対し、BINARY_DOUBLE 型の 2.5 に対してROUND 関数を実行すると 2.0 になっています。これは「銀行丸め」とか「偶数への丸め」と呼ばれる仕様です。端数が 0.5 の場合は偶数になるように丸めます。
ROUND(v) と ROUND(v, 0) の違い
ROUND 関数の第2パラメーターには小数点以下の桁数を指定します。この値を 0 に指定すると整数に丸められますが、BINARY_DOUBLE 型の列に対して実行すると結果が変わってきます。
SQL> SELECT c2, ROUND(c2), ROUND(c2, 0) FROM rd_table ORDER BY c1;
C2 ROUND(C2) ROUND(C2,0)
---------- ---------- -----------
2.1E+000 2.0E+000 2
2.2E+000 2.0E+000 2
2.3E+000 2.0E+000 2
2.4E+000 2.0E+000 2
2.5E+000 2.0E+000 3
2.6E+000 3.0E+000 3
2.7E+000 3.0E+000 3
2.8E+000 3.0E+000 3
2.9E+000 3.0E+000 3
3.0E+000 3.0E+000 3
10 rows selected.
c2 列が 2.4 の場合、ROUND(c2) は 2.0 が返りますが、ROUND(c2, 0) は 3 が返っています。
これは第2パラメーターに 0 を指定した場合、NUMBER 型として扱われるためです。
マニュアル には下記ようにわかりにくい記述があります。
nには、任意の数値データ型、または暗黙的に数値データ型に変換可能な数値以外のデータ型を指定できます。integerを指定しない場合、このファンクションは、nの数値データ型と同じデータ型で値ROUND(n, 0)を戻します。integerを指定すると、このファンクションはNUMBERを戻します。
他のRDBMSでは?
SQL Server や DB2 ではNUMERIC 型、FLOAT 型共に四捨五入がデフォルトになるようです。