私はmoney
データ型とdecimal(19,4)
のようなものの間に本当の違いがあるかどうかについて興味があります(それはお金が内部的に使うものです、と私は思います)。
私はmoney
がSQL Serverに特有であることを知っています。一方を選択する説得力のある理由があるかどうかを知りたいです。ほとんどのSQL Serverサンプル(AdventureWorksデータベースなど)は、価格情報などのためにmoney
ではなくdecimal
を使用します。
単にmoneyデータ型を使い続けるべきでしょうか、それとも代わりにdecimalを使うことに利点がありますか?お金は入力する文字数が少ないですが、それは正当な理由ではありません:)
あなたはお金を使うべきではありません。それは正確ではありません、そしてそれは純粋なゴミです。常に10進数/数値を使用してください。
これを実行して、私の言っていることを確認してください。
DECLARE
@mon1 MONEY,
@mon2 MONEY,
@mon3 MONEY,
@mon4 MONEY,
@num1 DECIMAL(19,4),
@num2 DECIMAL(19,4),
@num3 DECIMAL(19,4),
@num4 DECIMAL(19,4)
SELECT
@mon1 = 100, @mon2 = 339, @mon3 = 10000,
@num1 = 100, @num2 = 339, @num3 = 10000
SET @mon4 = @mon1/@mon2*@mon3
SET @num4 = @num1/@num2*@num3
SELECT @mon4 AS moneyresult,
@num4 AS numericresult
出力:2949.0000 2949.8525
お金でお金を分けないと言った人々の中には:
これが相関を計算するための私の質問の一つで、それをお金に変えると間違った結果が得られます。
select t1.index_id,t2.index_id,(avg(t1.monret*t2.monret)
-(avg(t1.monret) * avg(t2.monret)))
/((sqrt(avg(square(t1.monret)) - square(avg(t1.monret))))
*(sqrt(avg(square(t2.monret)) - square(avg(t2.monret))))),
current_timestamp,@MaxDate
from Table1 t1 join Table1 t2 on t1.Date = traDate
group by t1.index_id,t2.index_id
SQLMenaceはお金が不正確だと言った。しかし、あなたはお金をお金で割ったり割ったりしないでください! 3ドル×50セントはいくらですか。 150ドル?お金をスカラーで乗算/除算します。スカラーは10進数でなければなりません。
DECLARE
@mon1 MONEY,
@mon4 MONEY,
@num1 DECIMAL(19,4),
@num2 DECIMAL(19,4),
@num3 DECIMAL(19,4),
@num4 DECIMAL(19,4)
SELECT
@mon1 = 100,
@num1 = 100, @num2 = 339, @num3 = 10000
SET @mon4 = @mon1/@num2*@num3
SET @num4 = @num1/@num2*@num3
SELECT @mon4 AS moneyresult,
@num4 AS numericresult
正しい結果になります。
moneyresult numericresult --------------------- ---------------------- ----------------- 2949.8525 2949.8525
money
は、小数点以下4桁まで必要としない限りは有効であり、スカラー(お金を表すものではない)がdecimal
であることを確認してください。
自分のしていることがわからなければすべてが危険です
高精度の10進数型でもその日を節約することはできません。
declare @num1 numeric(38,22)
declare @num2 numeric(38,22)
set @num1 = .0000006
set @num2 = 1.0
select @num1 * @num2 * 1000000
1.000000 < - 0.6000000であるべき
money
型は整数です
smallmoney
とdecimal(10,4)
のテキスト表現は似ているかもしれませんが、それはそれらを交換可能にしません。日付がvarchar(10)
として保存されているのを見たときに、あなたはがっかりしていますか?これは同じことです。
舞台裏では、money
/smallmoney
は単なるbigint
/int
です。money
のテキスト表現の小数点は、yyyy-mm-ddの日付のダッシュのように視覚的にはっきりしたものです。 SQLは実際にはそれらを内部に格納しません。
decimal
とmoney
に関しては、ニーズに合ったものを選んでください。 money
型が存在するのは、アカウンティング値を単位の10000分の1の整数倍として格納するのが非常に一般的だからです。また、単純な足し算と引き算を超えて実際のお金と計算を扱うのであれば、データベースレベルでそれを行うべきではありません!アプリケーションレベルでそれを行うライブラリBanker's Rounding(IEEE 754)をサポート
私は、WayneMが、お金はSQL Serverに固有のものであることを知っていると述べたことを理解しています。しかし、彼は10進以上のお金を使う理由があるかどうかを尋ねています、そして私は1つの明白な理由がまだ述べられるべきであると思います - それは起こり得る。
システムをできるだけ柔軟にしてください。
まあ、私はMONEY
name__が好きです!これはDECIMAL
name__より1バイト安価であり、(隠れて)加算および減算演算は本質的に整数演算であるため、計算はより高速に実行されます。 @SQLMenaceの例(これは気付かない人にとってはすばらしい警告です)は、結果がゼロになるINT
name__egersにも同様に適用できます。しかし、整数を使用しない理由はありません。-適切な場合。
ですから、あなたが扱っているものがMONEY
name__であるときにMONEY
name__を使用し、それに続く数学的ルールに従って使用するのは完全に「安全」で適切です(INT
name__egerと同じ)。
SQL ServerがMONEY
name__のDECIMAL
name__s(またはFLOAT
name__s?)への除算と乗算を促進した場合、それは良かったのでしょうが、おそらくそうしなかったでしょう。また、それらを分割するときにINT
name__egersをFLOAT
name__sにプロモートすることも選択しませんでした。
MONEY
name__には精度の問題はありません。 DECIMAL
name__sが計算中に使用されるより大きな中間型を持つようになるということは、その型を使用することの「機能」にすぎません(その「機能」がどこまで拡張されるかは実際にはわかりません)。
特定の質問、「説得力のある理由」に答えるには?まあ、x
name__がDECIMAL
name__またはMONEY
name__のいずれかである可能性があるSUM(x)
で絶対的な最大パフォーマンスが必要な場合、MONEY
name__にはEdgeがあります。
また、小さいいとこ、SMALLMONEY
—わずか4バイトであることを忘れないでください。ただし、214,748.3647
で最大になります。
より大きな中間型を使用してそのポイントを証明するために、中間体を変数に明示的に割り当てた場合、DECIMAL
name__でも同じ問題が発生します。
declare @a decimal(19,4)
declare @b decimal(19,4)
declare @c decimal(19,4)
declare @d decimal(19,4)
select @a = 100, @b = 339, @c = 10000
set @d = @a/@b
set @d = @d*@c
select @d
2950.0000
を生成します(少なくとも、DECIMAL
name__が切り捨てられるのではなく、MONEY
name__が丸められます。整数と同じです)。
他の答えの一般的な推力へのカウンターポイントとして。 SQLCATのリレーショナルエンジンガイド のお金の多くの利点…データタイプ!を参照してください。
具体的には次のように指摘します。
顧客の実装に取り組んでいると、moneyデータ型に関して興味深いパフォーマンス値がいくつか見つかりました。たとえば、Analysis ServicesをSQL Serverのmoneyデータ型と一致するようにcurrencyデータ型(doubleから)に設定した場合、処理速度(行/秒)は13%向上しました。 SSIS 2008 - 世界記録のETLパフォーマンスに記載されているように、30分以内に1.18 TBをロードするためのSQL Server Integration Services(SSIS)内でのパフォーマンスの向上TPC-H LINEITEMテーブルの5バイトの列のサイズがmoney(8バイト)になると、バルク挿入速度が20%向上しました。これは、コンパクトなバイナリ形式で、SQL Serverの内部記憶形式にできるだけ近い形でデータを転送するための重要な設計原則です。経験的に、これはSSIS 2008 - Kernrateを使用した世界記録ETLパフォーマンステストの間に観察されました。データ型が10進数からmoneyに切り替えられると、プロトコルは大幅に低下しました。これにより、データ転送が可能な限り効率的になります。複雑なデータ型は、固定幅型よりも処理に追加の解析とCPUサイクルが必要です。
それで、質問への答えは「それは依存します」です。精度を維持するためには、特定の算術演算にもっと注意を払う必要がありますが、パフォーマンスを考慮するとこれが価値があることがわかります。
私たちは非常によく似た問題に遭遇したところで、今ではトップレベルのプレゼンテーションを除いてMoneyを決して使わないことに対して非常に+1しています。それぞれに履歴上の理由で1つ以上のMoneyフィールドが含まれる複数のテーブル(事実上、売上伝票と売上請求書)があります。合計請求額のうち、税のどれだけがそれぞれに関連するかを計算する必要があります。販売伝票の行私たちの計算は
vat proportion = total invoice vat x (voucher line value / total invoice value)
これにより、実社会の貨幣/貨幣の計算が行われ、その結果、分割部分にスケールエラーが発生し、それが誤ったバットの比率にまで増加します。これらの値が後で追加されると、合計請求額に加算されない付加価値税比率の合計になります。角括弧内の値のいずれかが10進数であれば(そのような値の1つをキャストしようとしています)、付加価値税率は正しいでしょう。
括弧が元々機能していなかったときは、値が大きいため効果的に高いスケールをシミュレートしていたと思います。括弧を追加したのは、最初に乗算を行っていたためです。これはまれに計算に使用できる精度を落とすことがありましたが、現在ではこれがはるかに一般的なエラーの原因となっています。
私は自分の専門知識と経験に基づいて、金額と数値の見方を変えたいと思います。ここでの私の視点は金額です。これはかなり長い間働いてきたので、実際に数値をあまり使わなかったからです。 。
お金プロ:
ネイティブデータ型。これは、CPUレジスタ(32または64ビット)と同じネイティブデータ型(integer)を使用するので、計算に不要なオーバーヘッドが不要なので小さいおよび速い... MONEYには8バイトが必要で、NUMERICAL(19、4) )9バイト(12.5%大きい)が必要です...
それはそれが(お金として)であることを意味していたために使用されている限りお金が速いです。どのくらい速いのか? 100万データに対する私の単純なSUM
テストは、MONEYが275ミリ秒、NUMERICが517ミリ秒であることを示しています...それはほぼ2倍の速さです...なぜSUMテスト?次を参照してくださいPropoint
お金コン:
money
はそれほど正確である必要はなく、単なるお金としてではありません。数...しかし...大きいですが、ここでもあなたのアプリケーションにリアルマネーが関係していますが、会計のようにSUM操作の多くでそれを使用しないでください。あなたが代わりにたくさんの除算と乗算を使うなら、あなたはお金を使うべきではありません...
値を掛け算/除算する必要があるときは、お金を使うべきではありません。 Moneyは整数と同じ方法で格納されますが、decimalは小数点と小数桁数として格納されます。これは、ほとんどの場合お金が正確さを落とすことを意味しますが、10進数は元のスケールに戻されたときにのみ正確さを落とします。お金は固定小数点なので、計算中にその規模は変わりません。ただし、(2進文字列の固定位置としてではなく)10進数文字列として印刷される場合は固定小数点であるため、4の位取りまでの値は正確に表現されます。だから足し算と引き算では、お金は大丈夫です。
10進数は10進数で内部的に表されるため、小数点の位置も10進数に基づいています。これは、お金の場合と同様に、小数部分が正確にその値を表すようにします。違いは、decimalの中間値は38桁までの精度を維持できるということです。
浮動小数点数では、値はまるでそれが整数であるかのように2進数で格納され、10進数(または2進数、ahem)の点の位置は数を表すビットに対する相対位置です。これは2進小数点であるため、10進数は小数点の直後の精度を失います。 1/5、つまり0.2は、この方法では正確に表現できません。お金も小数もこの制限を受けません。
お金を10進数に変換し、計算を実行し、その結果得られた値をMoneyのフィールドまたは変数に格納するのは簡単です。
私のPOVから、あまり考えないで数字に起こることがちょうど起こるようにしたいです。すべての計算が10進数に変換されるのであれば、私には10進数を使用したいと思います。私はお金のフィールドを表示目的で保存します。
サイズ的には、私の考えを変えるほどの違いはありません。 Moneyは4 - 8バイトを取りますが、decimalは5、9、13、および17にすることができます。9バイトは、8バイトのお金が可能な範囲全体をカバーできます。索引に関して(比較と検索は比較可能であるべきです)。
精度の問題で、お金よりも小数を使用する理由が見つかりました。
DECLARE @dOne DECIMAL(19,4),
@dThree DECIMAL(19,4),
@mOne MONEY,
@mThree MONEY,
@fOne FLOAT,
@fThree FLOAT
SELECT @dOne = 1,
@dThree = 3,
@mOne = 1,
@mThree = 3,
@fOne = 1,
@fThree = 3
SELECT (@dOne/@dThree)*@dThree AS DecimalResult,
(@mOne/@mThree)*@mThree AS MoneyResult,
(@fOne/@fThree)*@fThree AS FloatResult
それをテストして決定を下すだけです。
私はこのブログ記事を見たところです。SQL ServerにおけるMoney vs. Decimal。
これは基本的にお金には正確さの問題があると言っています...
declare @m money
declare @d decimal(9,2)
set @m = 19.34
set @d = 19.34
select (@m/1000)*1000
select (@d/1000)*1000
money
型の場合、19.34ではなく19.30となります。計算のためにお金を1000の部分に分割するアプリケーションシナリオがあるかどうかはわかりませんが、この例ではいくつかの制限があります。
これまでの投稿はすべて有効な点をもたらしていますが、その一部は正確に答えていません。
問題は、それがあまり正確ではないデータ型であり、複雑な計算に使用されるとエラーを引き起こす可能性があることをすでにわかっているのに、なぜ誰かがお金を好むのはなぜですか?
複雑な計算を行わずにこの精度を他のニーズと交換できる場合は、お金を使います。
たとえば、上記の計算を行う必要がなく、1バイトを節約する必要がある場合(お金には8バイト、10進数(19,4)には9バイトかかります)。
もう1つの例は、上記の計算をする必要がなく、大量のデータを処理するのに速度が必要な場合です。
別の例としては、上記の計算を行う必要がなく、有効な通貨テキスト文字列からインポートする必要がある場合です。他の数値型でこれを試してみてください。SELECT CONVERT(MONEY、 '$ 1,000.68')