web-dev-qa-db-ja.com

10進数の列にお金を保存する-精度とスケールは?

データベースにお金の値を格納するために小数列を使用していますが、今日はどの精度とスケールを使用するのかと思っていました。

おそらく固定幅のchar列の方が効率的であるため、小数列についても同じことが当てはまると考えていました。それは...ですか?

そして、どの精度とスケールを使用する必要がありますか?私は24/8の精度を考えていました。それはやり過ぎではありませんか?


これは私がやることに決めたものです。

  • 変換率(該当する場合)をトランザクションテーブル自体にfloatとして保存します
  • アカウントテーブルに通貨を保存する
  • 取引額はDECIMAL(19,4)になります
  • 変換率を使用するすべての計算はアプリケーションで処理されるため、丸めの問題を制御できます

コンバージョン率の浮動小数点数が問題になるとは思いません。ほとんどの場合参照用であり、とにかく小数にキャストするからです。

貴重なご意見ありがとうございます。

160
Ivan

万能型をお探しの場合は、DECIMAL(19, 4)が一般的な選択肢であることをお勧めします(簡単なGoogleがこれを裏付けています)。これは古いVBA/Access/Jet Currencyデータ型に由来し、言語の最初の固定小数点10進数型だと思います。 Decimalは、VB6/VBA6/Jet 4.0では「バージョン1.0」スタイルのみで実装されていました(つまり、完全には実装されていません)。

固定小数点の値のstorageの経験則は、実際に丸めを許可するために必要な小数点以下を少なくとも1つ以上保存することです。フロントエンドの古いCurrencyタイプをバックエンドのDECIMAL(19, 4)タイプにマッピングする理由の1つは、Currencyが本来バンカーの丸めを示したのに対し、DECIMAL(p, s)切り捨てによって。

DECIMALのストレージに余分な小数点があるため、ベンダーのデフォルトを使用するのではなく、カスタムの丸めアルゴリズムを実装できます(そして、控えめに言っても、銀行家の丸めは、.5で終わるすべての値ゼロから四捨五入)。

はい、DECIMAL(24, 8)はやり過ぎのように聞こえます。ほとんどの通貨は、小数点以下4桁または5桁で表示されます。私は、8(またはそれ以上)の小数スケールisが必要な状況を知っていますが、これは「通常の」金額(小数4桁など)が比例しており、小数精度を意味しますそれに応じて減らす必要があります(このような状況では浮動小数点型も考慮してください)。そして今日、24の10進精度を要求するほど多くのお金を持っている人はいません:)

ただし、万能のアプローチではなく、いくつかの研究が適切である場合があります。適用可能な会計規則については、設計者またはドメインエキスパートに問い合わせてください。GAAP、EUなど。小数点以下5桁に丸めるための明示的な規則があるEU州内転送を漠然と思い出します。したがって、DECIMAL(p, 6)を使用します。会計士は通常、小数点以下4桁を好むようです。


PS SQL ServerのMONEYデータ型は、移植性などの考慮事項の中でも特に、丸めの際に重大な問題があるため、避けてください。 Aaron Bertrandのブログ を参照してください。


ハードウェア設計者が選択したため、Microsoftと言語設計者は銀行家の丸めを選択しました[引用?]。たとえば、米国電気電子技術者協会(IEEE)標準に定められています。そして、数学者がそれを好むので、ハードウェア設計者はそれを選びました。 Wikipedia ;をご覧ください。言い換えると、1906年版の「確率とエラーの理論」では、この「コンピューターのルール」(「コンピューター」は計算を実行する人間を意味します)と呼ばれていました。

160
onedaywhen

最近、複数の通貨の値を処理し、それらの間で変換する必要があるシステムを実装し、いくつかの困難な方法を見つけました。

お金に浮動小数点数を使用しないでください

浮動小数点演算は不正確さをもたらしますが、それは何かを台無しにするまで気付かないかもしれません。すべての値は整数または固定小数点型として保存する必要があります。固定小数点型を使用する場合は、その型が内部で何を行うかを正確に理解してください(つまり、内部で整数または浮動小数点を使用します)タイプ)。

計算または変換を行う必要がある場合:

  1. 値を浮動小数点に変換する
  2. 新しい値を計算する
  3. 数値を丸めて整数に変換し直します

手順3で浮動小数点数を整数に変換するときは、キャストするだけでなく、数学関数を使用して最初に丸めます。これは通常roundになりますが、特別な場合にはfloorまたはceilになります。違いを知り、慎重に選択してください。

値と一緒に数値のタイプを保存する

1つの通貨のみを処理する場合、これはそれほど重要ではないかもしれませんが、複数の通貨を処理する上で重要でした。 USD、GBP、JPY、EURなどの通貨に3文字のコードを使用しました。

状況によっては、以下を保存することも役立ちます。

  • 番号が税の前か後か(および税率はどうだったか)
  • 数値が変換の結果であるかどうか(および変換元)

処理している数値の精度の限界を知る

実際の値の場合、通貨の最小単位と同じくらい正確になります。これは、セント、ペニー、円、フェンなどより小さい値がないことを意味します。理由もなく、それよりも高い精度で値を保存しないでください。

内部的には、より小さい値を扱うことを選択できます。その場合、それは異なる種類の通貨値です。どちらがどれであるかをコードが把握しており、それらが混同しないようにしてください。ここでも浮動小数点値を使用しないでください。


これらのルールをすべて追加して、次のルールを決定しました。実行中のコードでは、通貨は最小単位の整数を使用して保存されます。

class Currency {
   String code;       //  eg "USD"
   int value;         //  eg 2500
   boolean converted;
}

class Price {
   Currency grossValue;
   Currency netValue;
   Tax taxRate;
}

データベースでは、値は次の形式の文字列として保存されます。

USD:2500

これは、$ 25.00の値を保存します。通貨を処理するコードがデータベースレイヤー自体の中にある必要がないため、すべての値を最初にメモリに変換できるため、これを行うことができました。他の状況が他のソリューションに役立つことは間違いありません。


そして、私が以前にそれを明確にしなかった場合、フロートを使用しないでください!

93
Marcus Downing

MySQLでお金を処理する場合、お金の値の精度がわかっている場合はDECIMAL(13,2)を使用し、すぐに十分な近似値が必要な場合はDOUBLEを使用します。したがって、アプリケーションが最大1兆ドル(またはユーロまたはポンド)の金額を処理する必要がある場合、これは機能するはずです。

DECIMAL(13, 2)

または、 GAAP に準拠する必要がある場合は、次を使用します。

DECIMAL(13, 4)
3
pollux1er

小数点以下4桁は、世界最小の通貨サブユニットを格納する精度を提供します。マイクロペイメント(ナノペイメント?!)の精度が必要な場合は、さらに下げることができます。

私もDECIMALをDBMS固有のマネータイプよりも好んでいます。アプリケーションIMOでそのようなロジックを保持する方が安全です。同じ行に沿った別のアプローチは、単純に[long]整数を使用し、アプリケーションレベルで人間の可読性(¤=通貨記号)のために¤unit.subunitにフォーマットすることです。

2
bobince

DBで何らかの種類の算術演算(請求レートの乗算など)を行う場合は、おそらく、ここで説明したよりもはるかに高い精度が必要になります。アプリケーションコードで倍精度浮動小数点値未満のものを使用したい。

1
Hank Gay

場合によっては1セント未満に移動する必要があり、非常に大きな悪魔を使用する国際通貨があります。たとえば、トランザクションごとに0.088セントを顧客に請求できます。私のOracleデータベースでは、列はNUMBER(20,4)として定義されています

1
WW.

SQL Serverのmoneyデータ型は、小数点以下4桁です。

SQL Server 2000 Books Onlineから:

通貨データは、正または負の金額を表します。 Microsoft®SQL Server™2000では、金銭データはmoneyおよびsmallmoneyデータ型を使用して保存されます。通貨データは、小数点以下4桁の精度で保存できます。 moneyデータ型を使用して、-922,337,203,685,477.5808から+922,337,203,685,477.5807の範囲の値を格納します(値を格納するには8バイトが必要です)。 smallmoneyデータ型を使用して、-214,748.3648から214,748.3647の範囲の値を格納します(値を格納するには4バイトが必要です)。小数点以下の桁数を増やす必要がある場合は、代わりに小数点データ型を使用してください。

1
Austin Salonen

ここで遅い答えですが、私は使用しました

DECIMAL(13,2)

99,999,999,999.99まで許可する必要があると考えています。

0
Mike Upjohn

IBM Informix Dynamic Serverを使用している場合、MONCYタイプはDECIMALまたはNUMERICタイプのマイナーバリアントです。常に固定小数点型です(一方、DECIMALは浮動小数点型にすることができます)。 1〜32の位取り、および0〜32の精度を指定できます(デフォルトは16の位取り、2の精度です)。したがって、保存する必要があるものに応じて、DECIMAL(16,2)を使用することがあります。これは、米国連邦赤字を維持するのに十分な大きさで、セントに最も近い値です。

0

私は、大部分について、あなたまたはあなたのクライアントの要件が、どの精度とスケールを使用するかを決定すべきだと思います。たとえば、私が取り組んでいるeコマースWebサイトでは、GBPのみでお金を扱うため、Decimal(6、2)に保つ必要があります。

0
ayaz