SE の雑記

SQL Server の情報をメインに Microsoft 製品の勉強内容を日々投稿

SQL Server の四捨五入について

leave a comment

丸めを行うための関数として ROUND がありますが製品によって、算術型丸め (四捨五入)/ 銀行型丸め (ISO 丸め) のどちらで実施されるかが変わってきます。

SQL Server で ROUND を使う場合、クエリ内 / SSIS で使用する場合が多いと思います。
各機能の ROUND の仕様は以下のようになっています。

ROUND (Transact-SQL)
ROUND (SSIS 式)

Microsoft 製品の ROUND の動作に関しては以下の技術情報に記載がされています。
丸めを行うカスタム プロシージャを実装する方法
[OFFXP]VBAのRound関数について

SQL Server の場合は算術型丸めが行われます。

以下の関数は、対称的な算術型丸めを行います。

Excel の Round() ワークシート関数
SQL Server の Round() 関数

一般的な四捨五入による、丸めが行われるため、2.5 を Round した場合は 3 となります。

image

SSIS も同様に算術型丸めとなるようです。
Decimal 型の列に対して派生列で Round したものを RoundColumn として設定した結果をデータビューアーで確認した結果がこちらになります。
SSIS の Round も算術型丸めの動作となっていました。
# 今回試しているのは、SQL Server 2012 の SSIS になります。
image

VBA の場合は銀行型丸めとなっています。

VBA では、数値関数 CByte()、CInt()、CLng()、CCur()、および Round() が銀行型丸めを行います。
Excel のワークシート関数には銀行型丸めを行う関数はありません。

 

VBA だけでなく VBScript も銀行型丸めが行われるようです。
2.5 を ROUND した場合は四捨五入による丸めをした場合は 3 になりますが、VBScript の Round は銀行型丸めとなり、近い偶数になるため 2 という結果になります。
image

 

それでは、小数点以下を保持するデータ型を整数型の列に格納した場合はどうなるでしょう。
image

Decimal (Numeric) の列を Int 型の列に派生列として置換する処理を SSIS で設定しています。
この場合、SSIS の派生列として設定した列の小数点以下の扱いは銀行型丸めの動作となるようですね。
# SSIS の INT 型に格納した際に値が銀行型丸めの処理で対応されているようですね。
image

SQL で以下のような更新をした場合には小数点以下の桁落ちが発生していました。

image

四捨五入をする場合、列に格納する前にきちんと四捨五入をして格納する必要があるようですね。

また、数値の精度が求められる場合には Float や Real 型のような概数型を使用しないようにする必要が出てきます。
小数型データ、浮動小数型データ、および実数型データの使用

金額のような正確な値が求められる列に概数型を使用していて、計算により値を求めている場合には微妙な誤差が発生してきて、その誤差の積み重ねが合計に影響を与えることがあります。
数値を扱う場合、データ型 / 丸めの処理がどのように影響するかを意識しておかないと精度の問題がでてくるので後々泣きが出てくるので注意しておくとよいかと。
# 保守していたシステムで概数型が使われていて微妙な誤差が発生したことはちょいちょいありますので…。

Written by masayuki.ozawa

11月 4th, 2012 at 1:52 pm

Posted in SQL Server

Tagged with

Leave a Reply

*