NUMERIC
/DECIMAL
Wie Joachim Isaksson sagte
, möchten Sie NUMERIC
verwenden /DECIMAL
Typ als Typ mit beliebiger Genauigkeit.
Zwei wichtige Punkte zu NUMERIC
/DECIMAL
:
- Lesen Sie das Dokument sorgfältig zu lernen, dass Sie die Skalierung angeben sollten, um die Standard-Skalierung von 0 zu vermeiden, d. h. ganzzahlige Werte, bei denen der Dezimalbruch abgeschnitten wird. Dies ist zwar einer der Orte, an denen Postgres von Standard-SQL abweicht (und Ihnen eine Skalierung bis zur Implementierungsgrenze ermöglicht). Daher ist es eine schlechte Wahl, die Skala nicht anzugeben.
- Die SQL-Typen
NUMERIC
&DECIMAL
sind nahe, aber nicht identisch nach dem SQL-Standard. In SQL:92 , Ihre angegebene Genauigkeit fürNUMERIC
respektiert wird, wohingegen fürDECIMAL
Der Datenbankserver darf über die von Ihnen angegebene hinaus zusätzliche Genauigkeit hinzufügen. Auch hier weicht Postgres etwas vom Standard ab, sowohl mitNUMERIC
&DECIMAL
dokumentiert als gleichwertig.
Bedingungen:
- Präzision ist die Gesamtzahl der Stellen in einer Zahl.
- Skalierung ist die Anzahl der Stellen rechts vom Dezimalkomma (der Dezimalbruch).
- ( Precision - Scale ) =Anzahl der Stellen links vom Dezimalkomma (ganzzahliger Anteil).
Stellen Sie die Spezifikationen Ihres Projekts für Präzision und Skalierung klar dar:
- Groß
Die Genauigkeit muss groß genug sein, um größere Zahlen zu verarbeiten, die in Zukunft benötigt werden. Das heißt… Vielleicht arbeitet Ihre App heute mit Tausenden von USD, muss aber in Zukunft Roll-up-Berichte erstellen, die in die Millionen gehen. - Klein
Für einige Buchhaltungszwecke müssen Sie möglicherweise einen Bruchteil des kleinsten Währungsbetrags speichern. Das heißt… mehr als 3 oder 4 Dezimalstellen statt der 2, die für einen Penny in USD benötigt werden .
Vermeiden Sie MONEY
eingeben
Postgres bietet ein MONEY
Typ auch. Das mag richtig klingen, ist aber für die meisten Zwecke wahrscheinlich nicht optimal. Ein Nachteil ist das mit MONEY
die Skalierung wird durch eine datenbankweite Konfigurationseinstellung festgelegt basierend auf Gebietsschema
. Diese Einstellung kann also gefährlich leicht variieren, wenn Sie den Server wechseln oder andere Änderungen vornehmen. Darüber hinaus können Sie diese Einstellung nicht für bestimmte Spalten steuern, während Sie die Skalierung für jede Spalte von NUMERIC
festlegen können Typ. Zum Schluss MONEY
ist kein Standard-SQL, wie in dieser Liste von Standard-SQL-Daten gezeigt Typen
. Postgres enthält MONEY
für Leute, die Daten von anderen Datenbanksystemen portieren möchten.
Verschieben Sie den Dezimalpunkt
Eine andere Alternative, die von einigen verwendet wird, ist das Verschieben des Dezimalkommas und das Speichern in einem großen ganzzahligen Datentyp.
Zum Beispiel beim Speichern von USD Dollar in den Cent, multiplizieren Sie eine beliebige Bruchzahl mit 100, wandeln Sie sie in einen ganzzahligen Typ um und fahren Sie fort. Beispiel:123,45 $ wird zur Ganzzahl 12.345.
Der Vorteil dieses Ansatzes sind schnellere Ausführungszeiten. Operationen wie sum
sind sehr schnell, wenn sie auf ganzen Zahlen ausgeführt werden. Ein weiterer Vorteil von Ganzzahlen ist die geringere Speichernutzung.
Ich finde diesen Ansatz nervig, verwirrend und riskant. Ärgerlich, weil Computer für arbeiten sollten uns, nicht gegen uns. Riskant, da einige Programmierer oder Benutzer es versäumen könnten, zu multiplizieren/dividieren, um zurück in Bruchzahlen 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 DECIMAL
haben /NUMERIC
in SQL und BigDecimal
in Java.
Rundung &NaN
Seien Sie bei der Programmierung Ihrer App sowie bei allen Berechnungen auf der Postgres-Serverseite sehr vorsichtig und achten Sie auf Rundungen und Kürzungen im Dezimalbruch. Und testen Sie auf unbeabsichtigte NaNs auftauchen.
Vermeiden Sie auf beiden Seiten, App und Postgres, immer Floating Point Datentypen für Geldarbeit. Gleitkommazahlen sind auf Leistungsgeschwindigkeit ausgelegt , aber auf Kosten der Genauigkeit . Berechnungen können zu scheinbar verrückten zusätzlichen Ziffern im Dezimalbruch führen. Nicht gut für Finanzen/Geld oder andere Zwecke, bei denen es auf Genauigkeit ankommt.
BigDecimal
Ja, in Java möchten Sie BigDecimal
als Ihren beliebigen Genauigkeitstyp. BigDecimal
ist langsamer und benötigt mehr Speicher, speichert aber Ihre Geldbeträge genau. SQL NUMERIC
/DECIMAL
sollte BigDecimal
zugeordnet werden wie hier
besprochen und auf StackOverflow
.
BigDecimal
ist eines der besten Dinge an Java. Ich kenne keine andere Plattform mit einer ähnlichen Klasse, insbesondere keine, die so gut implementiert und ausgefeilt ist, mit wichtigen Verbesserungen und Korrekturen, die im Laufe der Jahre vorgenommen wurden.
Verwenden von BigDecimal
ist definitiv langsamer als die Verwendung von Java-Gleitkommatypen
, float
&double
. Aber in realen Apps bezweifle ich, dass Ihre Geldberechnungen ein Engpass sein werden. Und außerdem, was wollen Sie oder Ihre Kunden:das schnellste Geldberechnungen oder genau Geld rechnen? 😉
Ich habe immer an BigDecimal
gedacht als das größte Schläfer-Feature in Java, der wichtigste Vorteil bei der Verwendung der Java-Plattform gegenüber so vielen anderen Plattformen, denen eine so ausgeklügelte Unterstützung für Bruchzahlen fehlt.
Ähnliche Frage:Bester Datentyp für Währung