Gelddaten zu PostgreSQL mit Java

8

Ich schreibe ein Java-Programm, das Währungsaustauschdaten mischt. Die Daten können mehrere Dezimalziffern wie "0.973047" haben. Nach einigen Recherchen konnte ich herausfinden, dass BigDecimal der richtige Datentyp für Java ist, aber welchen Datentyp sollte ich für PostgreSQL verwenden?

    
Arya 11.08.2013, 07:09
quelle

3 Antworten

20

NUMERIC / DECIMAL

Joachim Isaksson sagte , dass Sie NUMERIC /%Co_de% , als beliebiger Präzisionstyp.

Zwei wichtige Punkte zu DECIMAL / NUMERIC :

  • Lesen Sie das Dokument sorgfältig durch, um zu erfahren, dass Sie die Skalierung angeben müssen, um das zu vermeiden Standardskalierung von 0, dh ganzzahlige Werte, bei denen der Dezimalbruch abgeschnitten wird. Dies ist einer der Orte, an denen Postgres von Standard-SQL abweicht (Sie können also bis zum Implementierungslimit skalieren). Es ist also eine schlechte Wahl, die Skala nicht zu spezifizieren.
  • Die SQL-Typen DECIMAL & amp; NUMERIC sind nahe, aber nicht identisch gemäß dem SQL-Standard. In SQL: 92 wird die angegebene Genauigkeit für DECIMAL berücksichtigt, für NUMERIC hingegen der Datenbankserver erlaubt eine zusätzliche Genauigkeit, die über das hinausgeht, was Sie angegeben haben. Auch hier weicht Postgres etwas vom Standard ab, wobei sowohl DECIMAL & amp; NUMERIC dokumentiert als gleichwertig.

Begriffe:

  • Genauigkeit ist die Gesamtanzahl der Ziffern in einer Zahl.
  • Skalierung ist die Anzahl der Stellen rechts vom Dezimalpunkt (der Dezimalbruch).
  • (Precision - Scale) = Anzahl der Ziffern links vom Dezimalpunkt (Ganzzahl).

Machen Sie sich mit den Spezifikationen Ihres Projekts für Präzision und Skalierung vertraut:

  • Groß
    Die Genauigkeit muss groß genug sein, um größere Zahlen bewältigen zu können, die in Zukunft benötigt werden. Bedeutung ... Vielleicht funktioniert Ihre App heute in Tausenden von US-Dollar, muss aber in Zukunft Roll-up-Berichte erstellen, die in Millionenhöhe enden.
  • Klein
    Für einige buchhalterische Zwecke müssen Sie möglicherweise einen Bruchteil des kleinsten Währungsbetrags speichern. Bedeutung ... Mehr als 3 oder 4 Dezimalstellen anstelle der 2, die für einen Penny in USD benötigt werden.

Vermeiden Sie DECIMAL type

Postgres bietet auch einen MONEY -Typ an. Das klingt vielleicht richtig, aber wahrscheinlich nicht gut für die meisten Zwecke. Ein Nachteil ist, dass mit MONEY die Skalierung durch eine datenbankweite Konfigurationseinstellung basierend auf Gebietsschema . Diese Einstellung kann sich gefährlich ändern, wenn Sie den Server wechseln oder andere Änderungen vornehmen. Darüber hinaus können Sie diese Einstellung für bestimmte Spalten nicht steuern, während Sie die Skalierung für jede Spalte von MONEY type festlegen können. Schließlich ist NUMERIC kein Standard-SQL, wie in dieser Liste der SQL-Standarddatentypen . Postgres enthält MONEY für den Komfort von Benutzern, die Daten von anderen Datenbanksystemen portieren.

Verschieben Sie den Dezimalpunkt

Eine andere Alternative, die von einigen verwendet wird, ist das Verschieben des Dezimalpunkts und das Speichern im großen Integer-Datentyp.

Wenn Sie zum Beispiel USD Dollars für den Penny speichern, multiplizieren Sie jede beliebige Anzahl von Dezimalstellen mit 100, umgerechnet auf eine ganze Zahl Geben Sie ein und fahren Sie fort. Zum Beispiel wird $ 123.45 zur Ganzzahl 12.345.

Der Vorteil dieses Ansatzes ist eine schnellere Ausführung. Operationen wie MONEY sind sehr schnell, wenn sie in Ganzzahlen ausgeführt werden. Ein weiterer Vorteil von Ganzzahlen ist die geringere Speichernutzung.

Ich finde diesen Ansatz lästig, verwirrend und riskant. Ärgerlich, weil Computer für uns arbeiten sollten, nicht gegen uns. Riskant, weil ein Programmierer oder Benutzer es unterlassen kann, Multiplikationen / Divisionen zu verwenden, um zurück in die Bruchzahl zu konvertieren, was zu falschen Ergebnissen führt. Wenn Sie in einem System ohne gute Unterstützung für genaue Bruchzahlen arbeiten, ist dieser Ansatz möglicherweise eine akzeptable Problemumgehung.

Ich sehe keinen Vorteil darin, den Dezimalpunkt zu verschieben, wenn wir sum / DECIMAL in SQL und NUMERIC in Java.

Runden & amp; %Code%

Bei der Programmierung Ihrer App sowie bei allen Berechnungen, die auf der Server-Seite von Postgres durchgeführt werden, sollten Sie sehr vorsichtig und rundlich und verkürzt im Dezimalbruch beachten. Und teste nach unbeabsichtigten NaNs , die auftauchen.

Bei beiden Seiten, App und Postgres, vermeiden Sie immer Fließkomma Datentypen für Geldarbeit. Gleitkommazahl ist für Leistungsgeschwindigkeit ausgelegt, aber für die Genauigkeit . Berechnungen können zu scheinbar verrückten zusätzlichen Ziffern im Dezimalbruch führen. Nicht gut für finanzielle / finanzielle oder andere Zwecke, wo Genauigkeit wichtig ist.

BigDecimal

Ja, in Java möchten Sie NaN als Ihr beliebiger Präzisionstyp. BigDecimal ist langsamer und benötigt mehr Speicher, speichert aber genau Ihre Geldbeträge. SQL BigDecimal / BigDecimal sollte wie besprochen auf NUMERIC abgebildet werden hier und auf StackOverflow .

DECIMAL ist eines der besten Dinge über Java. Ich kenne keine andere Plattform mit einer ähnlichen Klasse, vor allem eine, die so gut implementiert und gut durchdacht ist, mit wichtigen Verbesserungen und Korrekturen, die im Laufe der Jahre gemacht wurden.

Die Verwendung von BigDecimal ist definitiv langsamer als die Java-Gleitkommatypen . BigDecimal & amp; %Code%. Aber in realen Apps bezweifle ich, dass Ihre Geldberechnungen einen Engpass darstellen. Und außerdem, was wollen Sie oder Ihre Kunden: die schnellsten Geldberechnungen oder genauen Geldberechnungen?

Basil Bourque 11.08.2013, 08:13
quelle
4

Um eine möglichst gute (und genaue) Genauigkeit zu erhalten, können Sie NUMERIC (oder sein Alias DECIMAL ), das eine hohe Genauigkeit hat und Ihnen erlaubt, die benötigte Genauigkeit zu bestimmen;

  

ZAHLEN

     

Benutzerdefinierte Genauigkeit, genau bis zu 131072 Stellen vor dem Komma; bis zu 16383 Nachkommastellen

    
Joachim Isaksson 11.08.2013 07:14
quelle
1

Im Allgemeinen sollte Geld nicht als Fließkomma gespeichert werden. Der beste Ansatz besteht normalerweise darin, den Geldbetrag als eine Ganzzahl der kleinsten zulässigen Größe (beispielsweise einen US-Cent) zu speichern und für die Eingabe und Anzeige zu formatieren. Dies ist im Wesentlichen eine Spalte DECIMAL mit fester Genauigkeit in SQL, aber wenn Sie sie zurück in Java übertragen, laufen Sie immer noch Gefahr, die Genauigkeit zu verlieren (z. B. was passiert, wenn Sie genau die Hälfte der letzten zulässigen Zahl teilen)?

    
chrylis 11.08.2013 07:48
quelle

Tags und Links