webentwicklung-frage-antwort-db.com.de

Geld in einer Dezimalspalte speichern - welche Genauigkeit und Skalierung?

Ich verwende eine Dezimalspalte, um Geldwerte in einer Datenbank zu speichern, und heute habe ich mich gefragt, welche Genauigkeit und Skalierung ich verwenden soll.

Da angeblich Zeichenspalten mit fester Breite effizienter sind, dachte ich, dass dies auch für Dezimalspalten gelten könnte. Ist es?

Und welche Präzision und Skalierung sollte ich verwenden? Ich habe 24/8 an Präzision gedacht. Ist das übertrieben, nicht genug oder in Ordnung?


Dafür habe ich mich entschieden:

  • Speichern Sie die Umrechnungskurse (falls zutreffend) in der Transaktionstabelle selbst als Float
  • Speichern Sie die Währung in der Kontotabelle
  • Der Transaktionsbetrag ist ein DECIMAL(19,4)
  • Alle Berechnungen mit einem Umrechnungskurs werden von meiner Anwendung verarbeitet, sodass ich die Kontrolle über Rundungsprobleme habe

Ich denke nicht, dass ein Float für die Conversion-Rate ein Problem ist, da es hauptsächlich als Referenz dient, und ich werde es sowieso auf eine Dezimalzahl umwandeln.

Vielen Dank für Ihre wertvollen Beiträge.

160
Ivan

Wenn Sie nach einer Einheitsgröße suchen, würde ich vorschlagen, dass DECIMAL(19, 4) eine beliebte Wahl ist (ein schneller Google bestätigt dies). Ich denke, dass dies vom alten VBA/Access/Jet Currency-Datentyp herrührt, der der erste Festkomma-Dezimaltyp in der Sprache ist. Decimal wurde in VB6/VBA6/Jet 4.0 nur in der Version 1.0 (d. h. nicht vollständig implementiert) angeboten.

Die Faustregel für die Speicherung von Festkomma-Dezimalwerten lautet, mindestens eine Dezimalstelle mehr zu speichern, als Sie tatsächlich für die Rundung benötigen. Einer der Gründe für die Zuordnung des alten Currency -Typs im Front-End zum DECIMAL(19, 4) -Typ im Back-End war, dass Currency von Natur aus eine Bankerrundung aufwies, während DECIMAL(p, s) gerundet durch Kürzung.

Eine zusätzliche Dezimalstelle im Speicher für DECIMAL ermöglicht die Implementierung eines benutzerdefinierten Rundungsalgorithmus, anstatt die Standardeinstellung des Anbieters zu übernehmen (und die Rundung der Banker ist gelinde gesagt alarmierend für einen Designer, der erwartet, dass alle Werte mit .5 enden von Null abrunden).

Ja, DECIMAL(24, 8) klingt für mich wie ein Overkill. Die meisten Währungen werden mit vier oder fünf Dezimalstellen angegeben. Ich kenne Situationen, in denen eine Dezimalskala von 8 (oder mehr) erforderlich ist , aber hier ein 'normaler' Geldbetrag (sagen wir vier Dezimalstellen). wurde anteilig bemessen, was bedeutet, dass die Dezimalgenauigkeit entsprechend reduziert werden sollte (unter solchen Umständen auch ein Gleitkommatyp in Betracht gezogen werden sollte). Und niemand hat heutzutage so viel Geld, um eine Dezimalgenauigkeit von 24 zu verlangen :)

Anstelle eines einheitlichen Ansatzes ist jedoch möglicherweise etwas Forschung angebracht. Fragen Sie Ihren Designer oder Domain-Experten nach den geltenden Rechnungslegungsregeln: GAAP, EU usw. Ich erinnere mich vage an einige EU-interne Überweisungen mit expliziten Regeln für die Rundung auf fünf Dezimalstellen, und verwende daher DECIMAL(p, 6) zur Speicherung . Buchhalter scheinen im Allgemeinen vier Dezimalstellen zu bevorzugen.


PS: Vermeiden Sie den Datentyp "MONEY" von SQL Server, da er beim Runden schwerwiegende Probleme mit der Genauigkeit aufweist, unter anderem hinsichtlich der Portabilität usw. Siehe Aaron Bertrands Blog .


Microsoft und Sprachdesigner entschieden sich für die Rundung von Bankern, weil Hardware-Designer sie gewählt hatten [Zitieren?]. Es ist beispielsweise in den Standards des Instituts für Elektrotechnik und Elektronik (IEEE) verankert. Und Hardware-Designer haben sich dafür entschieden, weil Mathematiker es vorziehen. Siehe Wikipedia ; Die Ausgabe von 1906 von Probability and Theory of Errors nannte dies "die Computerregel" ("Computer" bedeutet Menschen, die Berechnungen durchführen).

160
onedaywhen

Vor kurzem haben wir ein System implementiert, das Werte in mehreren Währungen verarbeiten und zwischen ihnen konvertieren muss, und einige Dinge auf die harte Tour herausgefunden.

NIEMALS SCHWIMMENDE PUNKTZAHLEN FÜR GELD VERWENDEN

Fließkomma-Arithmetik führt zu Ungenauigkeiten, die möglicherweise erst bemerkt werden, wenn sie etwas vermasselt haben. Alle Werte sollten entweder als Ganzzahlen oder als Festkommatypen gespeichert werden. Wenn Sie sich für die Verwendung eines Festkommatyps entscheiden, stellen Sie sicher, dass Sie genau wissen, was dieser Typ unter der Haube tut (dh verwendet er intern eine Ganzzahl oder einen Gleitkommawert) Art).

Wenn Sie Berechnungen oder Umrechnungen durchführen müssen:

  1. Konvertiert Werte in Gleitkommazahlen
  2. Neuen Wert berechnen
  3. Runden Sie die Zahl und konvertieren Sie sie zurück in eine Ganzzahl

Wenn Sie eine Gleitkommazahl in Schritt 3 zurück in eine Ganzzahl konvertieren, müssen Sie sie nicht nur umwandeln, sondern mit einer mathematischen Funktion zuerst runden. Dies ist normalerweise round, in besonderen Fällen jedoch floor oder ceil. Kennen Sie den Unterschied und wählen Sie sorgfältig.

Speichern Sie den Typ einer Zahl neben dem Wert

Dies ist möglicherweise nicht so wichtig für Sie, wenn Sie nur eine Währung verwalten, aber für uns war es wichtig, mehrere Währungen zu verwalten. Wir haben den dreistelligen Code für eine Währung wie USD, GBP, JPY, EUR usw. verwendet.

Je nach Situation kann es auch hilfreich sein, Folgendes zu speichern:

  • Ob die Nummer vor oder nach Steuern ist (und wie hoch der Steuersatz war)
  • Ob die Zahl das Ergebnis einer Konvertierung ist (und wovon sie konvertiert wurde)

Kenne die Genauigkeitsgrenzen der Zahlen, mit denen du es zu tun hast

Für reale Werte möchten Sie so genau sein wie die kleinste Einheit der Währung. Dies bedeutet, dass Sie keine Werte haben, die kleiner als ein Cent, ein Penny, ein Yen, ein Fen usw. sind. Speichern Sie Werte nicht ohne Grund mit höherer Genauigkeit.

Intern können Sie sich für kleinere Werte entscheiden. In diesem Fall handelt es sich um einen anderen Währungstyp . Stellen Sie sicher, dass Ihr Code weiß, welcher welcher ist, und dass er sie nicht durcheinander bringt. Vermeiden Sie auch hier die Verwendung von Gleitkommawerten.


Zusammengenommen haben wir uns für die folgenden Regeln entschieden. Im laufenden Code werden Währungen mit einer Ganzzahl für die kleinste Einheit gespeichert.

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

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

In der Datenbank werden die Werte als Zeichenfolge im folgenden Format gespeichert:

USD:2500

Das speichert den Wert von 25,00 $. Dies ist nur möglich, weil der Code, der sich mit Währungen befasst, nicht in der Datenbankebene selbst enthalten sein muss, sodass alle Werte zuerst in den Speicher konvertiert werden können. Andere Situationen bieten sich zweifellos für andere Lösungen an.


Und falls ich es nicht vorher klargestellt habe, benutze kein float!

93
Marcus Downing

Verwenden Sie beim Umgang mit Geld in MySQL DECIMAL (13,2), wenn Sie die Genauigkeit Ihrer Geldwerte kennen, oder DOUBLE, wenn Sie nur einen schnellen, ausreichend guten Näherungswert wünschen. Wenn Ihre Anwendung Geldwerte bis zu einer Billion Dollar (oder Euro oder Pfund) verarbeiten muss, sollte dies funktionieren:

DECIMAL(13, 2)

Oder, wenn Sie GAAP einhalten müssen, dann verwenden Sie:

DECIMAL(13, 4)
3
pollux1er

4 Dezimalstellen geben Ihnen die Genauigkeit, die kleinsten Währungseinheiten der Welt zu speichern. Sie können es weiter reduzieren, wenn Sie eine Genauigkeit für Mikropayment (Nanopayment ?!) benötigen.

Auch ich bevorzuge DECIMAL gegenüber DBMS-spezifischen Geldarten. Sie sind sicherer, wenn Sie diese Art von Logik in der Anwendung IMO beibehalten. Ein anderer Ansatz in der gleichen Richtung besteht darin, einfach eine [lange] Ganzzahl zu verwenden, wobei die Formatierung in ¤unit.subunit für die menschliche Lesbarkeit (¤ = Währungssymbol) auf Anwendungsebene erfolgt.

2
bobince

Wenn Sie in der DB arithmetische Operationen ausführen (Multiplikation der Abrechnungssätze usw.), möchten Sie wahrscheinlich aus den gleichen Gründen, die Sie niemals hätten, viel präziser sein, als die Leute hier vorschlagen möchten im Anwendungscode weniger als einen Gleitkommawert mit doppelter Genauigkeit verwenden.

1
Hank Gay

Manchmal müssen Sie weniger als einen Cent ausgeben, und es gibt internationale Währungen, die sehr große Dämonen verwenden. Beispielsweise können Sie Ihren Kunden 0,088 Cent pro Transaktion in Rechnung stellen. In meiner Oracle-Datenbank sind die Spalten als NUMBER (20,4) definiert.

1
WW.

Der Gelddatentyp in SQL Server besteht aus vier Nachkommastellen.

In der SQL Server 2000-Onlinedokumentation:

Gelddaten stehen für positive oder negative Geldbeträge. In Microsoft® SQL Server ™ 2000 werden Gelddaten mit den Datentypen money und smallmoney gespeichert. Währungsdaten können mit einer Genauigkeit von vier Dezimalstellen gespeichert werden. Verwenden Sie den Gelddatentyp, um Werte im Bereich von -922.337.203.685.477.5808 bis +922.337.203.685.477.5807 zu speichern (zum Speichern eines Werts sind 8 Byte erforderlich). Verwenden Sie den Smallmoney-Datentyp, um Werte im Bereich von -214.748,3648 bis 214.748,3647 zu speichern (zum Speichern eines Werts sind 4 Byte erforderlich). Wenn eine größere Anzahl von Dezimalstellen erforderlich ist, verwenden Sie stattdessen den Datentyp Dezimal.

1
Austin Salonen

Eine späte Antwort habe ich hier aber benutzt

DECIMAL(13,2)

was ich denke, sollte bis zu 99.999.999.999,99 zulassen.

0
Mike Upjohn

Wenn Sie IBM Informix Dynamic Server verwenden, haben Sie einen MONEY-Typ, bei dem es sich um eine geringfügige Variante des DECIMAL- oder NUMERIC-Typs handelt. Es ist immer ein Festkommatyp (während DECIMAL ein Gleitkommatyp sein kann). Sie können eine Skala von 1 bis 32 und eine Genauigkeit von 0 bis 32 angeben (standardmäßig eine Skala von 16 und eine Genauigkeit von 2). Je nachdem, was Sie speichern müssen, können Sie DECIMAL (16,2) verwenden, das immer noch groß genug ist, um das US-amerikanische Haushaltsdefizit auf den nächsten Cent zu bringen. Sie können auch einen kleineren Bereich oder mehr Dezimalstellen verwenden.

0

Ich würde meinen, dass die Anforderungen Ihrer oder Ihrer Kunden zum großen Teil bestimmen sollten, welche Präzision und welcher Maßstab verwendet werden sollen. Zum Beispiel musste ich für die E-Commerce-Website, an der ich arbeite, nur Geld in GBP auf Dezimal (6, 2) setzen.

0
ayaz