LoginSignup
1
1

SQL Server と .NET の decimal 型

Posted at

SQL Server の decimal 型のフィールドから、.NET アプリで ADO.NET を使って .NET の Decimal 型として値を取得する際、SQL Server と .NET では扱える値の大きさが異なる (SQL Server の方が大きい) ことにより、OverflowException が発生することがあるという話を書きます。

image (4).jpg

.NET の Decimal 型は、Microsoft のドキュメント「Decimal 構造体」によると、128 ビットで構成され、その内 96 ビットが整数部で、残り 32 ビットが正負の符号と小数点の位置を指定するのに使われているそうです。

従い、.NET の Decimal 型の最大値 (MaxValue) は、

2^96 - 1 = 79,228,162,514,264,337,593,543,950,335

ということになります。

一方、SQL Server の decimal 型は、Microsoft のドキュメント「decimal 型と numeric 型 (Transact-SQL)」によると、38 桁まで表すことができるそうです。例えば、decimal(38,0) は小数部の無い 38 桁の整数を表すことができるということになります。

上の画像では、.NET の Decimal.MaxValue より 1 大きい SQL Server の decimal(38,0) 型の値を、.NET のコンソールアプリで ADO.NET + System.Data.SqlClient を使って取得しようとして OverflowException が発生しています。

上のようなケースではオバーフローするのが当たり前と思えるのですが、自分がハマったのは SQL Server の decimal 型のフィールドで小数点が指定してある場合でした。そのことを以下に書きます。

なお、以下の話は System.Data.SqlClient を使った場合ですので注意してください。(Microsoft.Data.SqlClient の場合は後述します)

例えば、decimal(38,26) と言うように小数部の桁数も指定して、上の画像のコード例の内 query2 を以下のように変更したとします。

// 上の画像の query2 で、
// 79228162514264337593543950336 ⇒ 10000000
// decimal(38,0) ⇒ decimal(38,26)
// に変更
var query2 = "select cast(10000000 as decimal(38,26)) val";

この場合も OverflowException がスローされます。上の 10000000 という値は、上の回答の画像の例 MaxValue + 1 よりはるかに小さいのになぜオーバーフローするのでしょうか?

そこが分からなくてハマったのですが、どうやら以下のようなことらしいです。

上のコードの例では、10000000 の後に 26 個の 0 を続けた整数値を表現できなければならず、.NET の Decimal の整数部 96 ビットでは表現できない (MaxValue を超える) のでオバーフローするということのようです。

試しに上のコードの 10000000 を 792 および 793 に代えて実行してみました。

79200000000000000000000000000 < MaxValue < 79300000000000000000000000000

ということで 792 は OK でしたが、793 はオバーフローするという結果になりました。

Microsoft.Data.SqlClient を使った場合は話が違ってきます

System.Data.SqlClient も Microsoft.Data.SqlClient も整数部が 96 ビットというのは同じなので、一番上の画像のコード例のように MaxValue を超える整数を設定した場合はオバーフローするのは同じです。

ただし、Microsoft.Data.SqlClient の場合は、上に書いた例と同様に SQL Server の decimal 型に小数部の桁数を指定してもオーバーフローとはなりませんでした。

System.Data.SqlClient とは実装が変わったようです。ただ、どのように変わったのか、どこまで大丈夫なのかは調べ切れてません。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1