SQL Server/SQL Database再入門 第1回 Decimal型とMoney型の違い
小数点を含む計算は難しい
プログラミングの世界の小数点を含む計算というのは難しいと私は思っています。注意しているつもりなのですが、過去に何度も何度も小数点が絡む部分で不具合を作りこんできました。なので、小数点を含む計算をするときには以下を確認するようにしています。
- 10進数なのか2進数なのか
- リテラル(ソースコードに数値や文字列を直接に記述した定数)に割り当てられる型は何か
- 異なる型同士の計算をした場合、結果の型は何になるのか
- 有効桁を超えた場合はどのような挙動になるのか
小数点をSQL Serverで扱う際に特に紛らわしいと感じるのがDecimal型とMoney型の二つの型があることです。この二つはまったく異なる性質を持っているのですが、似たようなものととしてなんとなく扱われている開発現場もあるのではないかと思います。
Money型とDECIMAL(19,4)型の違い
以下をみてください。
DECLARE @money1 MONEY
DECLARE @money2 MONEY
DECLARE @money4 MONEY
DECLARE @decimal1 DECIMAL(19,4)
DECLARE @decimal2 DECIMAL(19,4)
DECLARE @decimal4 DECIMAL(19,4)
SET @money1 = 10
SET @money2 = 3
SET @money4 = @money1 / @money2
SET @decimal1 = 10
SET @decimal2 = 3
SET @decimal4 = @decimal1 / @decimal2
SELECT @money4 AS [money], @decimal4 AS [decimal]
今度は以下を実行してみましょう。
SET @money1 = 10
SET @money2 = 3
SET @money3 = 10000
SET @money4 = @money1 / @money2 * @money3
SET @decimal1 = 10
SET @decimal2 = 3
SET @decimal3 = 10000
SET @decimal4 = @decimal1 / @decimal2 * @decimal3
SELECT @money4 AS [money], @decimal4 AS [decimal]
今度はさきほどとは異なり、違う結果になってしまいました。
どちらも同じ数値「3.3333」に「10000」を掛けただけです。それなのにMONEY型の結果は「33333.00」になり、DECIMAL(19,4)は「33333.3333」になったのです。
違いを調べる
実際にそれぞれの型を指定してテーブルを作って確認しています。結果をみるとLength(長さ、バイト数)の部分に違いがありますが、それ以外は何も違わないように見えます。
CREATE TABLE MoneyDecimal (
money1 MONEY,
decimal1 DECIMAL(19,4)
);
GO
EXEC sp_help MoneyDecimal;
GO
計算列を定義して、計算後の型がどうなっているのか確認してみると、明確な違いがでてきます。Money型同志の掛け算の結果は長さ(バイト数)も有効桁も小数点の位置も変わりませんが、Decimal(19, 4)型の同志の掛け算の結果は長さ(バイト数)も有効桁も小数点の位置も変わってしまっていることが分かると思います。
CREATE TABLE MoneyDecimal (
money1 MONEY,
money2 AS money1 * money1,
decimal1 DECIMAL(19,4),
decimal2 AS decimal1 * decimal1
);
GO
EXEC sp_help MoneyDecimal;
GO
つまり、Decimalは計算内容によって型が変わる場合があるということです。もう少しいろんなパターンを試してみましょう。
CREATE TABLE MoneyDecimal (
money1 MONEY,
decimal1 DECIMAL(19,4),
[decimal + decimal] AS decimal1 + decimal1,
[decimal - decimal] AS decimal1 - decimal1,
[decimal / decimal] AS decimal1 / decimal1,
[decimal * decimal] AS decimal1 * decimal1,
[money + decimal] AS money1 + decimal1,
[money - decimal] AS money1 - decimal1,
[money / decimal] AS money1 / decimal1,
[money * decimal] AS money1 * decimal1,
[decimal + money] AS decimal1 + money1,
[decimal - money] AS decimal1 - money1,
[decimal / money] AS decimal1 / money1,
[decimal * money] AS decimal1 * money1
);
GO
要するに、Decimal型の場合、演算をすると演算結果はなるべ丸めないように有効桁や小数点が調整されるということです。
一方でMoney型の場合は小数点の位置は固定されており、切り捨てが発生します。内部的に整数として値を保持して演算していて、最後に小数点を調整するような挙動になっているのかなと思っています。
参考情報
- money と smallmoney (Transact-SQL) - SQL Server | Microsoft Docs
- decimal 型と numeric 型 (Transact-SQL) - SQL Server | Microsoft Docs
シリーズ SQL Server/SQL Database再入門
なんとなくならSQL Serverを使えている人のためのSQL Server/SQL DatabaseのTips集です。
Author And Source
この問題について(SQL Server/SQL Database再入門 第1回 Decimal型とMoney型の違い), 我々は、より多くの情報をここで見つけました https://qiita.com/yyukawa/items/c1e23a97d4170edba23f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .