Bester Datentyp zum Speichern von Geldwerten in MySQL

279

Ich möchte viele Datensätze in einer MySQL-Datenbank speichern. Alle von ihnen enthalten Geldwerte. Aber ich weiß nicht, wie viele Ziffern für jede eingefügt werden.
Welchen Datentyp muss ich dafür verwenden?
VARCHAR oder INT (oder andere numerische Datentypen)?

Mohammad Saberi
quelle
13
deimal(10,2)ist, was ich benutze ... Sie können die Werte abhängig von der erwarteten Größe anpassen
Manse
9
Verwandte Frage ist Bester Datentyp für Währung ;).
shA.t

Antworten:

370

Da Geld eine genaue Darstellung benötigt, verwenden Sie keine Datentypen, die nur ungefähr sind float. Sie können dafür einen numerischen Festkomma-Datentyp verwenden

decimal(15,2)
  • 15 ist die Genauigkeit (Gesamtlänge des Wertes einschließlich Dezimalstellen)
  • 2 ist die Anzahl der Nachkommastellen

Siehe MySQL Numeric Types :

Diese Typen werden verwendet, wenn es wichtig ist, die genaue Genauigkeit beizubehalten, beispielsweise bei Gelddaten .

Jürgen d
quelle
3
Was könnte in diesem Fall der Unterschied zwischen dezimalem und numerischem Datentyp sein?
Emilio Gort
60
In MySQL decimalund numericsind gleich.
Jürgen d
21
Ich persönlich verwende es numeric(19,4)für Finanzunterlagen, mit denen Sie leichter spielen und neue Anfragen problemlos annehmen können.
YahyaE
10
Ich stimme YahyaE zu, mehr Dezimalstellen sind besser. Es gibt einige Währungen, die normalerweise 3 Dezimalstellen verwenden, z. B. die bahrainischen, jordanischen oder kuwaitischen Dinare. Sie benötigen also mindestens 3. Vier oder fünf sind besser.
Edwin Hoogerbeets
1
@EdwinHoogerbeets Ich bin kein Buchhalter ... aber ich leite ein kleines Geschäft in Großbritannien ... Ich erinnere mich, dass ich vor langer Zeit irgendwo gelesen habe, dass Währungszahlen sogar für £, $ usw. auf 4 Dezimalstellen gespeichert werden sollten, damit bestimmte Berechnungen möglich sind Verwenden Sie tatsächlich die letzten 2 Dezimalstellen für bestimmte undurchsichtige Buchhaltungskontexte. Wir brauchen einen Buchhalter, um zu bestätigen / zu widerlegen.
Mike Nagetier
88

Sie können verwenden DECIMALoder NUMERICbeide sind gleich

Die Typen DECIMAL und NUMERIC speichern exakte numerische Datenwerte. Diese Typen werden verwendet, wenn es wichtig ist, die genaue Genauigkeit beizubehalten, beispielsweise bei Gelddaten. In MySQL ist NUMERIC als DECIMAL implementiert, daher gelten die folgenden Anmerkungen zu DECIMAL gleichermaßen für NUMERIC. : MySQL

dh DECIMAL(10,2)

Beispieleinstellungen

Gut gelesen

NullPoiиteя
quelle
3
Vielleicht verwirrend, aber Ihr Screenshot stimmt nicht mit Ihrem Antworttext überein (Präzision, Skalierung).
Patrick Hofman
Ich verwende Dezimalzahl (10,2) für meinen Geldwert. Wenn ich jedoch so etwas wie 867.000,00 eingebe, wird es als 867 gespeichert. Was mache ich falsch?
Codeinprogress
32

Ich bevorzuge es BIGINT, die Werte zu verwenden und zu speichern, indem ich sie mit 100 multipliziere , damit sie ganzzahlig werden.

Um beispielsweise einen Währungswert von darzustellen 93.49, wird der Wert als gespeichert 9349, während der Wert angezeigt wird , den wir durch 100 teilen und anzeigen können. Dies belegt weniger Speicherplatz.

Achtung:
Meistens führen wir keine currency * currencyMultiplikation durch. Wenn wir dies tun, teilen Sie das Ergebnis durch 100 und speichern Sie es, damit es wieder die richtige Genauigkeit erreicht.

Dinesh PR
quelle
Ich erinnere mich, dass mir ein Professor in meinem Universitätskurs für Computersysteme etwas Ähnliches erzählt hat. Mir wurde beigebracht, dass der genaueste Weg darin besteht, in Pennies (oder Cent) zu speichern, indem man mit 100 multipliziert und als Ganzzahl speichert und durch 100 dividiert, um sie dem Benutzer anzuzeigen. Ich denke, dies hat Vorteile in Bezug auf Genauigkeit und Leistung des Datenbanksystems.
LondonAppDev
11
Was ist der Vorteil gegenüber DECIMAL? Sie müssen Pennies in Dollar umrechnen, und wehe, wenn Sie es irgendwann vergessen.
1
Platz ist der einzige Vorteil, aber ja, wir müssen vorsichtiger sein, wenn wir diese Funktion verwenden.
Dinesh PR
4
Falls es nicht offensichtlich ist: Seien Sie vorsichtig bei der Verwendung der Methode zum Entfernen von Skalen, wenn Sie Geld in Bruchteilen von Cent (z. B. $0.005oder $0.12345) speichern, da diese nach dem Multiplizieren mit 100 nicht auf eine Ganzzahl reduziert werden. Wenn Sie die Genauigkeit der Werte kennen, ist dies klar beste Option ist zu verwenden DECIMAL. Aber wenn Sie die Präzision nicht kennen (wie in meinen Beispielen), dann ... wäre FLOATdas angemessen?
Quinn Comendant
1
Ein Vorteil dieser Methode ergibt sich bei Verwendung einer Sprache wie JavaScript, die IEEE-754 zum Speichern von Gleitkommazahlen verwendet. Diese Spezifikation garantiert nicht, dass 0,1 + 0,2 === 0,3 wahr ist. Das Speichern der Währung als Ganzzahl gibt die Gewissheit, dass Ihre Anwendung diese Art von Fehler nicht verursacht. Dies ist jedoch möglicherweise nicht die beste Lösung. Ich bin auf dieser Seite angekommen, als ich nach Lösungen gesucht habe, und bin noch nicht fertig.
Gary Ott
27

Es hängt von Ihren Bedürfnissen ab.

DECIMAL(10,2)Normalerweise reicht die Verwendung aus, aber wenn Sie etwas genauere Werte benötigen, können Sie diese einstellen DECIMAL(10,4).

Wenn Sie mit großen Werten arbeiten, ersetzen Sie 10durch 19.

Svetoslav
quelle
Ich verwende Dezimalzahl (10,2) für meinen Geldwert. Wenn ich jedoch so etwas wie 867.000,00 eingebe, wird es als 867 gespeichert. Was mache ich falsch?
Codeinprogress
2
@codeinprogress Verwenden Sie das falsche Gebietsschema / Dezimaltrennzeichen?
David Balažic
15

Wenn Ihre Anwendung Geldwerte bis zu einer Billion verarbeiten muss, sollte dies funktionieren: 13,2 Wenn Sie GAAP (General Accepted Accounting Principles) einhalten müssen, verwenden Sie: 13,4

Normalerweise sollten Sie Ihre Geldwerte bei 13,4 summieren, bevor Sie die Ausgabe auf 13,2 runden.

david.ee
quelle
5
Wenn Sie Bitcoin nehmen möchten, benötigen Sie 8 Dezimalstellen, obwohl die meisten Geldbörsen an mBTC gehen, das ist 3 en.wikipedia.org/wiki/Bitcoin
Christian
Glaube nicht, dass diese Antwort wahr ist. opendata.stackexchange.com/a/10348/13983 @ david.ee hat eine Quelle dafür?
Evan Carroll
@EvanCarroll lass mich für david.ee antworten. Ich denke, dieser Artikel kann die Quelle sein rietta.com/blog/2012/03/03/best-data-types-for-currencymoney-in
naXa
@naXa Der Link zitiert nichts aus einer Quelle, die den Anspruch unterstützt, 13,4 für GAAP zu verwenden. Alles, was Sie getan haben, war ein Link zu einem Artikel, der dieselbe unbegründete Behauptung aufstellt.
Iheanyi
6

Dies hängt in der Tat von den Vorlieben des Programmierers ab. Ich persönlich verwende: numeric(15,4)um die allgemein anerkannten Rechnungslegungsgrundsätze ( GAAP ) einzuhalten .

Chagbert
quelle
5
Es hat überhaupt nichts mit "Programmiererpräferenzen" oder dem, was Sie "persönlich verwenden", zu tun. Dies wird durch die Problemdomäne vorgegeben, für die ein Dezimalradix erforderlich ist. Dies ist keine Angelegenheit, in der der Programmierer seine eigenen persönlichen Vorlieben ausüben kann.
Marquis von Lorne
3

Versuchen Sie es mit

Decimal(19,4)

Dies funktioniert normalerweise auch mit jeder anderen Datenbank

Deepesh
quelle
3

Wir benutzen double.

*keuchen*

Warum?

Weil es eine beliebige 15-stellige Zahl ohne Einschränkungen für den Dezimalpunkt darstellen kann . Alles für nur 8 Bytes!

So kann es darstellen:

  • 0.123456789012345
  • 123456789012345.0

... und alles dazwischen.

Dies ist nützlich, da es sich um globale Währungen handelt und doubledie verschiedenen Dezimalstellen gespeichert werden können, auf die wir wahrscheinlich stoßen werden.

Ein einzelnes doubleFeld kann 999.999.999.999.999 in japanischen Yen, 9.999.999.999.999,99 in US-Dollar und sogar 9.999.999.99999999 in Bitcoins darstellen

Wenn Sie versuchen, dasselbe mit zu tun decimal, benötigen Sie, decimal(30, 15)was 14 Bytes kostet.

Vorsichtsmaßnahmen

Natürlich ist die Verwendung doublenicht ohne Einschränkungen.

Allerdings ist es nicht Genauigkeitsverlust , wie einige darauf hinweisen neigen. Auch wenn doublees für das Basis-10-System intern möglicherweise nicht genau ist , können wir es genau machen, indem wir den Wert, den wir aus der Datenbank ziehen, auf seine signifikanten Dezimalstellen runden . Bei Bedarf ist das so. (zB Wenn es ausgegeben werden soll und eine Darstellung der Basis 10 erforderlich ist.)

Die Einschränkungen sind, dass wir jedes Mal, wenn wir damit rechnen, das Ergebnis normalisieren müssen (indem wir es auf seine signifikanten Dezimalstellen runden), bevor:

  1. Vergleiche durchführen.
  2. Schreiben Sie es zurück in die Datenbank.

Eine andere Art von Einschränkung besteht darin, dass im Gegensatz dazu, decimal(m, d)wo die Datenbank verhindert, dass Programme eine Zahl mit mehr als mZiffern einfügen , keine derartigen Überprüfungen vorhanden sind double. Ein Programm könnte einen vom Benutzer eingegebenen Wert von 20 Stellen einfügen und wird dann stillschweigend als ungenauer Betrag aufgezeichnet.

Antak
quelle
Zum ersten Mal habe ich eine Antwort wie diese gesehen, interessant. F: Wenn ich einen Float wie 1.41 in die Datenbank schreibe und aus irgendeinem Grund muss ich ihn mit einer großen Zahl in MySQL multiplizieren, wie z. B. 1.000.000.000.000. Wird das gerundete Ergebnis genau sein: 1.410.000.000.000?
Roelleor
@roelleor Damit das Ergebnis genau 1.410.000.000.000 (Komma als Tausendertrennzeichen) ist, wird angenommen, dass die Eingabe 1.410000000000(zwölf signifikante Dezimalstellen) ist. Wenn Sie diese jedoch mit 1.000.000.000.000 multiplizieren (das sind 13 signifikante Stellen, die vom Dezimalpunkt entfernt sind), arbeiten wir mit at mindestens 25 kombinierte Stellen von Bedeutung. Dies übertrifft die 15, die für ein Doppel verfügbar sind, bei weitem, was das Design betrifft, denke ich, dass es sehr kaputt wäre.
Antak
2

Zu der Zeit, als diese Frage gestellt wurde, dachte niemand über den Bitcoin-Preis nach. Im Fall von BTC ist die Verwendung wahrscheinlich nicht ausreichend DECIMAL(15,2). Wenn der Bitcoin auf 100.000 US-Dollar oder mehr steigt, müssen wir mindestens DECIMAL(18,9)Kryptowährungen in unseren Apps unterstützen.

DECIMAL(18,9)nimmt in MySQL 12 Bytes Speicherplatz in Anspruch ( 4 Bytes pro 9 Ziffern ).

bizwiz
quelle
> Ein Bitcoin kann in 8 Dezimalstellen unterteilt werden. Daher ist 0,00000001 BTC der kleinste Betrag, der in einer Transaktion verarbeitet werden kann. Ich denke du meinst 8 statt 9?
Gefahr89
1
Ich weiß, aber 9 belegt den gleichen Speicherplatz wie 8. Aus MySQL-Dokumenten: "Werte für DECIMAL-Spalten werden in einem Binärformat gespeichert, das neun Dezimalstellen in 4 Bytes packt"
bizwiz
Tut mir leid, jetzt verstehe ich dich. Vielen Dank.
Gefahr89
2

Das Speichern von Geld BIGINTmultipliziert mit 100 oder mehr mit dem Grund, weniger Speicherplatz zu verbrauchen, macht in allen "normalen" Situationen keinen Sinn.

  • Um mit GAAP in Einklang zu bleiben, reicht es aus, Währungen in zu speichern DECIMAL(13,4)
  • Das MySQL-Handbuch liest, dass es 4 Bytes pro 9 Ziffern zum Speichern benötigt DECIMAL.
  • DECIMAL(13,4) repräsentiert 9 Stellen + 4 Bruchstellen (Dezimalstellen) => 4 + 2 Bytes = 6 Bytes
  • Vergleiche mit 8 Bytes, die zum Speichern benötigt werden BIGINT.
digitalstraw
quelle