PostgreSQL:通貨にはどのデータ型を使用すべきですか?


128

ここにMoney記載されているように、タイプは推奨されないようです

アプリケーションは通貨を格納する必要があります。どのデータ型を使用する必要がありますか?数値、お金、またはFLOAT?


7
スレッド全体を読んだ場合は、Numericが適しています。
razpeitia 2013年

複数の通貨で作業し、金額に加えて通貨コードを保存することに関心がある人は、データベース(SO)とISO 4217(Wikipedia)で通貨モデリングを確認することをお勧めします。つまり、2つの列が必要になります。
Fabien Snauwaert、

回答:


90

数値強制2単位の精度の。floatまたはfloat like datatypeを使用して通貨を表すことは絶対にしないでください。通貨を表すと、財務報告の最終的な数値が+または-数ドルずれると、人々は不満を感じるようになります。

お金の種類は、私が知る限り、歴史的な理由で残っています。


9
それが浮動小数点を避ける理由ではありません。使用する精度に関係なく、10の累乗に分割されないもので除算すると、数値でも丸め誤差が発生します。(とにかく2の精度は悪い考えです...ドキュメントを確認してください。)
Doradus

6
任意の通貨をサポートする場合は、スケールを2に等しくしないでください(postgresqlの用語では、精度はすべての桁数です。たとえば、121.121では6に等しくなります)。バーレーンディナールなど、1000のサブユニットが1ユニットに相当する通貨があり、サブユニットをまったく持たない通貨もあります。
Nikolay Arhipov

@NikolayArhipov良い点なので、最大は実際にありますscale - precision
Konrad

1
numeric(3,2)最大を保存できるようになります9.99 3-2 = 1
Konrad

5
こんなことしないで!他の言語に値をロードする前に100を掛けて整数で計算を行うことを計画していない限り、誤った結果が得られます。物事をセント(あなたが扱っている最小の通貨単位)で保管し、面倒を省いてください。多くの場合、非常に悪い答えです。
アバマンダー

111

あなたの情報源は決して公式ではありません。それは2011年までさかのぼります、そして、私さえ著者を認識しません。お金のタイプが公式に「非推奨」である場合、PostgreSQLはマニュアルでそう述べています- それはしません

より公式なソースについて、pgsql-generalでこのスレッドを読んでください(今週から)、D'Arcy JM Cain(moneyタイプの元の作者)やTom Laneなどのコア開発者からの声明。

最近のリリースの改善に関する関連回答(およびコメント!):

基本的に、money(非常に限られた)用途があります。Postgresのウィキは、これらの狭義の場合を除き、大部分はそれを避けるために示唆しています。利点numericパフォーマンスです。

decimalnumericPostgresの単なる別名であり、通貨データに広く使用されており、「任意精度」タイプです。マニュアル

この型numericは、桁数が非常に多い数値を格納できます。これは、正確性が要求される金額やその他の量を保存する場合に特に推奨されます。

個人的には、integer端数セントが発生しない場合(基本的にはお金が意味をなす場合)は、通貨をセントを表すものとして保存します。これは、言及された他のどのオプションよりも効率的です。


4
お金のタイプは少なくとも推奨されないという印象を与える、メーリングリストに関するいくつかの議論があります。例:ここ:postgresql.nabble.com/Money-type-todos-td1964190.html#a1964192さらに公平にするため:バージョン8.2のマニュアルで非推奨と呼ばれていました:postgresql.org/docs/8.2/static/datatype-money.html
a_horse_with_no_name

11
@a_horse_with_no_name:リンクは2007年のスレッドへのリンクです。これは、8.2が現在のバージョンであり、moneyタイプが実際には非推奨であった場合でもあります。問題が修正され、タイプが新しいバージョンに追加されました。個人的に私integerはセントを表すものとして通貨を保存するのが好きです。
Erwin Brandstetter 2015年

1
アーウィン、あなたはデータベースの観点だけでは正しい考えかもしれません。ただし、Postgresql + Javaを組み合わせた場合、(私の経験から)まったく良くありません。コメントを読んで、通貨フィールドのほとんどにMONEYを使用しましたが、次のJava例外が発生しました: " SQLExceptionが発生しました:org.postgresql.util.PSQLException:タイプdoubleの値が不正です:2,500.00 "。私はググって良い解決策を見つけられなかったので、私はそれらすべてを今NUMERICまたはDECIMALに変更するという退屈な仕事に夢中です!!!
MDは

1
@MD:それを聞いて申し訳ありませんが、私は明らかにJavaについて話しませんでした(私はできません)。エラーメッセージは奇妙です。"ダブル"?そして、千単位の区切り文字も問題になる可能性があります。あなたはそれについて新しい質問を始めたいと思うかもしれません。
Erwin Brandstetter、2015年

2
@PirateApp:はい、私の個人的なお気に入りです。あなたは私の答えの最後の文を見逃しているかもしれません。
Erwin Brandstetter 2018年

68

選択肢は次のとおりです。

  1. bigint:セントで金額を保存します。これはEFTPOSトランザクションが使用するものです。
  2. decimal(12,2):小数点以下2桁で金額を格納します。これは、最も一般的な元帳ソフトウェアが使用するものです。
  3. float:ひどい考え-不十分な精度。これは、素朴な開発者が使用するものです。

オプション2が最も一般的で、最も扱いやすい方法です。精度(この例では12、つまり全体で12桁を意味します)を、最適な大きさまたは大きさにします。

計算の結果である複数のトランザクション(たとえば、為替レートを含む)をビジネス上の意味を持つ単一の値に集約する場合、正確なマクロ値を提供するために精度を高くする必要があることに注意してください。decimal(18, 8)合計が正確になり、個々の値をセント精度に丸めて表示できるようにするなどの使用を検討してください。


10
何らかの逆税金計算または外国為替を使用している場合、少なくとも小数点以下4桁が必要です。そうしないと、データが失われます。それで、numeric(15,4)またはnumeric(15,6)良い考えです。
ペトルスセロン2017年

3
4番目のオプションがあります。つまり、文字列を使用し、ホスト言語で同等の非可逆10進数型を使用します。
ioquatix 2017

2
スケーリングされた整数はどうですか、1000x45を確実に格納しても、1000倍のスケーリング係数で10000045として格納されていれば害はありませんか?
PirateApp 2018年

26

私はすべての通貨フィールドを次のように保持しています。

numeric(15,6)

小数点以下の桁数が多すぎることは過度に思われますが、わずかな可能性でも複数の通貨を処理する必要がある場合は、変換にその精度が必要になります。ユーザーに何を提示する場合でも、常に米ドルで保管します。このようにして、当日の換算レートを考えると、他の通貨に簡単に換算できます。

1つの通貨以外に何もしない場合、ここで最悪のことは、いくつかのゼロを格納するために少しのスペースを無駄にしたことです。


6
切り捨てが行われないため、これは誤った結果になるリスクがあります。0.333333ドルを含む価格フィールドなど、ゼロ以外の値が意図せずに小数点以下の残りの桁に漏れた場合、システムが、誰かがそれぞれ0.33ドルで3つの商品を購入した結果、合計が0.99ドルではなく1.00ドルになるという結果になることがあります。
Peteris

1
ペルテリス、代わりに何を提案しますか?この丸めでどれだけの精度を投げても問題になることがあります。これが理想的でなくても、私はもっと良い方法を見つけられませんでした。
マイケルコレット

3
固定小数点と適切な場所で切り捨てます。顧客に提供される価格などの「保存可能な」金額に達するとすぐに、それは適切なメトリックに含まれるはずです。これは、ほとんどの場合、標準的な小売環境では1セントになります。さまざまなビジネスニーズがある場合(たとえば、1単位あたりの大量商品の価格)は、精度の設定が異なる可能性がありますが、プレゼンテーションをストレージと一緒に扱う必要があります。小数xで通貨番号を表示する場合(またはその逆の場合)たとえば、数千単位で)、その精度で保存する必要があります。
Peteris

うまくいくかもしれない多くの小売関連サイトのために。私が扱う主なプロジェクトでは、あるサードパーティが、ある通貨で同じコストを、別の通貨でクライアントと、サプライヤーの3番目のコストを確認する必要があるかもしれません。
マイケルコレット

19

次のように保存された64ビット整数を使用します bigint

マイクロドル(または同様の主要通貨)を使用することをお勧めします。マイクロは100万分の1を意味するので、1マイクロドル= 0.000001ドルです。

  • 使いやすく、すべての言語と互換性があります。
  • セントの端数を処理するのに十分な精度。
  • 非常に小さな単位あたりの料金で機能します(広告のインプレッションやAPIの料金など)。
  • 文字列や数値よりも格納用のデータサイズが小さい。
  • 計算を通じて精度を維持し、最終出力で丸めを適用するのは簡単です。

1
これが最も正しい答えであり、妥当なソフトウェアは手元にある最小の通貨単位を扱います。整数に対してすべての計算を行うと、言語固有の浮動小数点変換を処理する必要がなくなります。
アバマンダー

1
それも使用します。ありがとう

なぜこれnumeric(15,6)は別の答えで示唆されているのですか?
Juliusz Gonera

@JuliuszGonera答えにリストされている理由のため。整数はより小さく、どこでもサポートされており、すべての数学の切り捨て問題を回避します。基本的に数値を使用していますが、小数をシフトしているため、より互換性のある整数になります。
マニガンダム

1
ああ、そうです、私はストレージに関する部分を逃しました。ありがとう!「使用が簡単ですべての言語と互換性がある」ことに関して、JavaScriptは残念ながら最大値の1000倍よりも小さい9007199254740991までの整数をサポートしていますbigintdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…がありますが、サポートは限定されており(現時点では)、警告があります(たとえば、通貨換算時にフロートを簡単に掛けることはできません)。 。マイクロドルを使用してJS整数に格納できる最大値が90億ドルであることを考えると、ほとんどの場合、それでもおそらく十分です。
Juliusz Gonera

3

BigInt通貨を最小の通貨単位で表す正の整数として格納するために使用します(たとえば、1.00ドルを格納するには100セント、100円を格納するには100セント(日本円、10進ゼロの通貨)。これはStripeが行うことです-1グローバルeコマースにとって最も重要な金融サービス会社。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.