Sollten Sie die Datentypen MONEY oder DECIMAL (x, y) in SQL Server auswählen?


442

Ich bin gespannt, ob es einen echten Unterschied zwischen dem moneyDatentyp und so etwas gibt decimal(19,4)(was Geld intern verwendet, glaube ich).

Mir ist bekannt, dass dies moneyspezifisch für SQL Server ist. Ich möchte wissen, ob es einen zwingenden Grund gibt, einen über den anderen zu wählen. Die meisten SQL Server-Beispiele (z. B. die AdventureWorks-Datenbank) verwenden moneyund nicht decimalfür Dinge wie Preisinformationen.

Sollte ich den Gelddatentyp einfach weiter verwenden, oder hat die Verwendung von Dezimalzahlen einen Vorteil? Geld besteht aus weniger Zeichen, aber das ist kein gültiger Grund :)


12
DECIMAL(19, 4) Dies ist eine beliebte Wahl. Überprüfen Sie dies auch hier. Weltwährungsformate, um zu entscheiden, wie viele Dezimalstellen verwendet werden sollen. Hoffnung hilft.
Shaijut

Ich habe mich gefragt, warum der Gelddatentyp 4 Dezimalstellen hat. Und nicht 2. Also 100 Cent in einem Dollar, also sind nur 2 Dezimalstellen erforderlich. Um einen Datensatz mit Geldbeträgen von weniger als 9999,99 USD zu speichern, wollte ich einen Datentyp mit Dezimalzahl (6,2) verwenden. Ich mache mir keine Sorgen um das Teilen oder Multiplizieren von Berechnungen, sondern nur um das Speichern und Summieren.
Allan F

Antworten:


326

Niemals sollten Sie Geld verwenden. Es ist nicht genau und es ist reiner Müll; Verwenden Sie immer dezimal / numerisch.

Führen Sie dies aus, um zu sehen, was ich meine:

DECLARE
    @mon1 MONEY,
    @mon2 MONEY,
    @mon3 MONEY,
    @mon4 MONEY,
    @num1 DECIMAL(19,4),
    @num2 DECIMAL(19,4),
    @num3 DECIMAL(19,4),
    @num4 DECIMAL(19,4)

    SELECT
    @mon1 = 100, @mon2 = 339, @mon3 = 10000,
    @num1 = 100, @num2 = 339, @num3 = 10000

    SET @mon4 = @mon1/@mon2*@mon3
    SET @num4 = @num1/@num2*@num3

    SELECT @mon4 AS moneyresult,
    @num4 AS numericresult

Ausgabe: 2949.0000 2949.8525

Zu einigen Leuten, die sagten, dass Sie Geld nicht durch Geld teilen:

Hier ist eine meiner Fragen zur Berechnung von Korrelationen, und die Änderung in Geld führt zu falschen Ergebnissen.

select t1.index_id,t2.index_id,(avg(t1.monret*t2.monret)
    -(avg(t1.monret) * avg(t2.monret)))
            /((sqrt(avg(square(t1.monret)) - square(avg(t1.monret))))
            *(sqrt(avg(square(t2.monret)) - square(avg(t2.monret))))),
current_timestamp,@MaxDate
            from Table1 t1  join Table1 t2  on t1.Date = traDate
            group by t1.index_id,t2.index_id

61
"Niemals" ist ein starkes Wort. "Geld" ist nützlich, um Ergebnisse auf diesen Typ zu übertragen, um sie dem Benutzer auf kulturempfindliche Weise anzuzeigen, aber Sie haben Recht, dass es sehr schlecht ist, sie für die Berechnungen selbst zu verwenden.
Joel Coehoorn

36
Ihr Beispiel ist nicht aussagekräftig, da niemand jemals zwei Objekte vom Typ Geld multiplizieren wird. Wenn Sie Ihren Standpunkt beweisen möchten, müssen Sie das Multiplizieren eines Geldes mit einer Dezimalstelle mit dem Multiplizieren einer Dezimalstelle mit einer Dezimalstelle vergleichen.
Brian

27
.. aber es ist immer noch rätselhaft, warum Geld * Geld nicht die Präzision von Geld haben würde.
Lernen

4
@Learning: Es hat eine Präzision von Geld. Es kommt jedoch immer noch zu Rundungsfehlern, die sich im Laufe der Zeit ansammeln können. Der Dezimaltyp verwendet keine binäre Arithmetik: Er garantiert, dass er die gleichen Basis-10-Ergebnisse erzielt, die Sie auf Papier erzielen würden.
Joel Coehoorn

55
Multiplikation und Division von moneyOver moneybeiseite, diese "Illustration" ist manipulativ. Es ist eine dokumentierte Tatsache, moneydie eine feste und sehr begrenzte Genauigkeit hat. In solchen Fällen sollte man zuerst multiplizieren und dann dividieren. Wenn Sie in diesem Beispiel die Reihenfolge der Operatoren ändern, erhalten Sie identische Ergebnisse. A ist im moneyWesentlichen ein 64-Bit-Int, und wenn Sie sich mit Ints befassen würden, würden Sie vor dem Teilen multiplizieren.
Andriy M

272

SQLMenace sagte, Geld sei ungenau. Aber Sie multiplizieren / teilen Geld nicht durch Geld! Wie viel kostet 3 Dollar mal 50 Cent? 150 Dollar? Sie multiplizieren / dividieren Geld durch Skalare, die dezimal sein sollten.

DECLARE
@mon1 MONEY,
@mon4 MONEY,
@num1 DECIMAL(19,4),
@num2 DECIMAL(19,4),
@num3 DECIMAL(19,4),
@num4 DECIMAL(19,4)

SELECT
@mon1 = 100,
@num1 = 100, @num2 = 339, @num3 = 10000

SET @mon4 = @mon1/@num2*@num3
SET @num4 = @num1/@num2*@num3

SELECT @mon4 AS moneyresult,
@num4 AS numericresult

Ergebnisse im richtigen Ergebnis:

Geldergebnis numerisches Ergebnis
--------------------- ----------------------------- ----------
2949,8525 2949,8525

moneyist gut, solange Sie nicht mehr als 4 Dezimalstellen benötigen und sicherstellen, dass Ihre Skalare - die kein Geld darstellen - decimals sind.


57
Wie viele 1-Cent-Münzen kann ein Dollarschein Ihnen bringen? Eine Antwort darauf erfordert Geld / Geld.
Lernen

48
@Lernen in diesem Fall ist das Ergebnis kein Geld, sondern ein Float. (Grundlegende Dimensionsanalyse.)
Richard

11
@Learning: Fragen Sie die Datenbank, wie viele Cent in einem Dollar viel sind? Auf jeden Fall würde das das richtige Ergebnis liefern. Sein Problem war, dass Geld / Geld nur auf vier Ziffern genau war (es war 0,2949), und wenn es mit 10000 multipliziert wurde, wurde es 2949,0000.
Konfigurator

26
@mson Er hat Recht und macht keine persönlichen Kritikpunkte, wie Sie es aufgrund einer einzeiligen Bemerkung getan haben. Es ist nicht hilfreich. Wenn er nicht durch 0,01 USD dividiert, sondern durch 0,01, ergibt sich ein Ergebnis von 100 USD anstelle von 100. Ein Dollar enthält 100 Cent, nicht 100 USD. Einheiten sind wichtig! Es gibt definitiv einen großen Ort, um Geld für Geld zu tauchen und vielleicht zu multiplizieren.
Andrew

19
Wenn ich 1000 US-Dollar ausgeben möchte, um Aktien zu einem Preis von 36 US-Dollar zu kaufen, ist das nicht eine legitime Verwendung von money / money? Die Antwort sind ganze Einheiten ohne Dollarzeichen, was richtig ist! Dies ist ein durchaus vernünftiges Szenario, das darauf hindeutet, dass aufgrund seltsamer Randfälle wie dieser moneykein guter Datentyp zu verwenden ist, da das Ergebnis immer wieder abgeschnitten wird, um zu passen, moneyanstatt den normalen Regeln für Präzision und Skalierung zu folgen. Was ist, wenn Sie die Standardabweichung einer Reihe von moneyWerten berechnen möchten ? Ja, Sqrt(Sum(money * money))(vereinfacht) macht tatsächlich Sinn.
ErikE

59

Alles ist gefährlich, wenn Sie nicht wissen, was Sie tun

Selbst hochpräzise Dezimaltypen können den Tag nicht retten:

declare @num1 numeric(38,22)
declare @num2 numeric(38,22)
set @num1 = .0000006
set @num2 = 1.0
select @num1 * @num2 * 1000000

1.000000 <- Sollte 0.6000000 sein


Die moneyTypen sind ganze Zahlen

Die Textdarstellungen von smallmoneyund decimal(10,4)mögen gleich aussehen, aber das macht sie nicht austauschbar. Erschrecken Sie, wenn Sie Daten als gespeichert sehen varchar(10)? Das ist das gleiche.

Hinter den Kulissen sind money/ smallmoneynur ein bigint/ int Der Dezimalpunkt in der Textdarstellung von moneyist visueller Flaum, genau wie die Bindestriche in einem JJJJ-MM-TT-Datum. SQL speichert diese nicht intern.

Wählen Sie in Bezug auf decimalvs money, was für Ihre Bedürfnisse geeignet ist. Die moneyTypen existieren, weil das Speichern von Abrechnungswerten als ganzzahlige Vielfache von 1/10000 der Einheit sehr häufig ist. Wenn Sie mit tatsächlichem Geld und Berechnungen zu tun haben, die über das einfache Addieren und Subtrahieren hinausgehen, sollten Sie dies nicht auf Datenbankebene tun! Führen Sie dies auf Anwendungsebene mit einer Bibliothek durch, die Banker's Rounding (IEEE 754) unterstützt.


1
Können Sie erklären, was in diesem Beispiel passiert ist?
Sergey Popov

4
Skalenüberlauf. Bei kleinen Maßstäben ergibt numerisch (a, b) * numerisch (c, d) numerisch (a-b + c-d + 1, max (b, d)). Wenn jedoch (a + b + c + d)> 38 ist, begrenzt SQL die Skalierung und beraubt die Präzision von der Bruchseite, um die Ganzzahlseite aufzufüllen, was den Rundungsfehler verursacht.
Anon

Alle numerischen Berechnungen können aufgrund von Skalierung an Genauigkeit verlieren: Berechnen Sie stattdessen select 1000000 * @ num1 * @ num2
Mitch Wheat

Anons Beispiel ist version und datenbankspezifisch. aber der Punkt, sei vorsichtig, ist gültig. In sqlanywhere Version 1.1 gibt das Beispiel 0.600000 korrekt an. (Ich weiß, wir sprechen hier über MS SQL). Ein weiterer Punkt, bei dem der Geldtyp in einer anderen Datenbank fehlt, ist die Möglichkeit, Dezimalzahlen oder Zahlen als Geld zu bezeichnen, z. B. das Erstellen einer Domain.
gg89

3
Ich denke, dies ist die aufschlussreichste Antwort, weil Sie nicht nur die Fehler erklärt haben, die sich verbreiten, sondern auch, was wirklich hinter den Kulissen vor sich geht und warum GELD überhaupt existiert. Ich bin mir nicht sicher, warum es 4 Jahre gedauert hat, um diese Antwort zu erhalten, aber vielleicht liegt es daran, dass zu viel Wert auf das Berechnungsproblem gelegt wird und nicht so sehr auf das Warum und Wie von Geld gegen Dezimalzahl.
Steve Sether

44

Mir ist klar, dass WayneM erklärt hat, dass er weiß, dass Geld spezifisch für SQL Server ist. Er fragt jedoch, ob es Gründe gibt, Geld über Dezimalzahl zu verwenden oder umgekehrt, und ich denke, ein offensichtlicher Grund sollte noch angegeben werden, und die Verwendung von Dezimalzahl bedeutet, dass Sie sich weniger Sorgen machen müssen, wenn Sie jemals Ihr DBMS ändern müssen - was passieren kann.

Machen Sie Ihre Systeme so flexibel wie möglich!


1
Möglicherweise, aber theoretisch könnten Sie eine Domain mit dem Namen Money in einem anderen DBMS deklarieren (das die Deklaration von Domains unterstützt).
Debater

Als jemand, der derzeit eine SQL Server-Datenbank in Amazon Redshift konvertiert, kann ich dafür bürgen, dass dies ein echtes Problem ist. Vermeiden Sie Datentypen, die auf eine bestimmte Datenbankplattform zugeschnitten sind, es sei denn, es gibt sehr gute geschäftliche Gründe, sie zu verwenden.
Nathan Griffiths

@Nathn Angesichts des schwachen Redshift-Typsystems im Vergleich zu PostgreSQL oder SQL Server, z. B. ohne dateTyp, würde ich sagen, dass Sie immer solche Probleme haben werden. Sie sollten sagen "Verwenden Sie keine veralteten Typen, wenn die Datenbank bereits bessere, standardkonformere Typen bereitstellt und vor den veralteten Typen warnt ".
Panagiotis Kanavos

@ PanagiotisKanavos - Geld ist nicht veraltet
Martin Smith

@MartinSmith war schockiert darüber, da es 2017 nicht mit Geldwerten wie BTC umgehen kann. Oder zwischen GBP- und EUR-Beträgen unterscheiden kann - obwohl sie sich in Richtung Parität bewegen: P. Wie auch immer, der Wechsel zu Redshift
bringt

32

Nun, ich mag MONEY! Es ist ein Byte billiger als DECIMALund die Berechnungen werden schneller ausgeführt, da Additions- und Subtraktionsoperationen (unter dem Deckmantel) im Wesentlichen ganzzahlige Operationen sind. Das Beispiel von @ SQLMenace - eine großartige Warnung für INTUnbewusste - könnte auch auf Eger angewendet werden, bei denen das Ergebnis Null wäre. Dies ist jedoch kein Grund, gegebenenfalls keine Ganzzahlen zu verwenden .

Es ist also absolut "sicher" und angemessen zu verwenden, MONEYwenn es sich um das handelt, womit Sie es zu tun haben, MONEYund es gemäß den folgenden mathematischen Regeln zu verwenden (wie bei INTeger).

Wäre es besser gewesen, wenn SQL Server die Division und Multiplikation von MONEY's in DECIMALs (oder FLOATs?) Gefördert hätte - möglicherweise, aber sie haben sich nicht dafür entschieden; Sie haben sich auch nicht dafür entschieden, INTEger zu FLOATs zu befördern, wenn sie sie teilen.

MONEYhat kein Präzisionsproblem; Dass DECIMALein größerer Zwischentyp bei Berechnungen verwendet wird, ist nur ein "Merkmal" der Verwendung dieses Typs (und ich bin mir nicht sicher, wie weit sich dieses "Merkmal" erstreckt).

Um die spezifische Frage zu beantworten, ein "zwingender Grund"? Nun, wenn Sie in eine absolute Höchstleistung wollen , SUM(x)wo xkönnte entweder DECIMALoder MONEY, dann MONEYwird die Nase vorn haben.

Vergessen Sie auch nicht, dass es ein kleinerer Cousin ist - SMALLMONEYnur 4 Bytes, aber es ist maximal 214,748.3647- was für Geld ziemlich klein ist - und daher oft nicht gut passt.

Wenn Sie das Intermediate explizit einer Variablen zuweisen, tritt DECIMALdas gleiche Problem auf, um die Verwendung größerer Zwischentypen zu beweisen :

declare @a decimal(19,4)
declare @b decimal(19,4)
declare @c decimal(19,4)
declare @d decimal(19,4)

select @a = 100, @b = 339, @c = 10000

set @d = @a/@b

set @d = @d*@c

select @d

Produziert 2950.0000(okay, also zumindest DECIMALgerundet anstatt MONEYabgeschnitten - genau wie eine ganze Zahl.)


21
MONEYist ein Byte kleiner als ein großes DECIMAL , mit bis zu 19 Stellen Genauigkeit. Die meisten realen Geldberechnungen (bis zu 9,99 Mio. USD) können jedoch in a passen DECIMAL(9, 2), was nur fünf Bytes erfordert. Sie können Größe sparen, sich weniger um Rundungsfehler kümmern und Ihren Code portabler machen.

Während @JonofAllTrades korrekt ist, können Sie die Leistung von Ganzzahlen auch zurückerhalten, indem Sie einfach eine Ganzzahl verwenden, die Pennies oder Cent enthält, und das zusätzliche Byte speichern, das die Position des Dezimalpunkts codiert und das beim Addieren von Dezimalstellen überprüft werden muss.
dsz

"Es ist also absolut 'sicher' und angemessen, GELD zu verwenden, wenn es sich um GELD handelt, und es nach den folgenden mathematischen Regeln zu verwenden" -> siehe jedoch auch Anons Antwort: "Alles ist gefährlich, wenn Sie es nicht tun weiß was du tust ". Sie können nie vorhersagen, wie die Leute das von Ihnen erstellte System abfragen werden, um die Möglichkeit eines Missbrauchs zu vermeiden, wenn Sie können. Der winzige Speichergewinn ist es meiner Meinung nach nicht wert.
Nathan Griffiths

1
Versuchen Sie, einen Bitcoin-Wert zu speichern. Es hat 8 Dezimalstellen
Panagiotis Kanavos

13

Wir sind gerade auf ein sehr ähnliches Problem gestoßen, und ich bin jetzt ein +1, weil ich Geld nur in Präsentationen auf oberster Ebene verwendet habe. Wir haben mehrere Tabellen (effektiv einen Verkaufsgutschein und eine Verkaufsrechnung), von denen jede aus historischen Gründen ein oder mehrere Geldfelder enthält, und wir müssen eine anteilige Berechnung durchführen, um herauszufinden, wie viel von der gesamten Rechnungssteuer für jede relevant ist Zeile auf dem Verkaufsgutschein. Unsere Berechnung ist

vat proportion = total invoice vat x (voucher line value / total invoice value)

Dies führt zu einer realen Geld / Geld-Berechnung, die Skalierungsfehler im Teilungsteil verursacht, die sich dann zu einem falschen Mehrwertsteuerverhältnis multiplizieren. Wenn diese Werte anschließend addiert werden, erhalten wir eine Summe der Mehrwertsteueranteile, die sich nicht zum Gesamtrechnungswert addieren. Wäre einer der Werte in den Klammern eine Dezimalzahl gewesen (ich werde einen davon als solchen umwandeln), wäre der Mehrwertsteueranteil korrekt.

Wenn die Klammern ursprünglich nicht da waren, funktionierte dies früher, ich denke, aufgrund der größeren Werte simulierte es effektiv eine höhere Skala. Wir haben die Klammern hinzugefügt, weil zuerst die Multiplikation durchgeführt wurde, was in einigen seltenen Fällen die für die Berechnung verfügbare Genauigkeit beeinträchtigte, aber dies hat jetzt diesen viel häufigeren Fehler verursacht.


8
Dies geschieht jedoch nur, weil ein ignoranter Entwickler die Regeln für Mehrwertsteuerberechnungen und die dokumentierten Genauigkeitsbeschränkungen von Geld ignoriert hat.
TomTom

1
@TomTom, aber der Punkt, den Sie über die Möglichkeit eines Missbrauchs dieses Datentyps ansprechen, ist ein Argument dafür, die Verwendung überhaupt nicht zu verwenden.
Nathan Griffiths

@ Nathan Nein. Ich weise darauf hin, dass das Argument, das als Grund angegeben wurde, es niemals zu verwenden, im Grunde genommen inkompetenter Entwickler ist, also ist das Argument falsch.
TomTom

1
@TomTom Leider gibt es viele inkompetente Entwickler (sowie viele großartige) und für mich, es sei denn, ich könnte garantieren, wie diese Daten in Zukunft abgefragt werden und niemand würde jemals die hier beschriebenen Fehler machen , besser auf Nummer sicher gehen und einen Dezimaltyp verwenden. Nachdem ich all diese Antworten gelesen habe, kann ich sehen, dass es einige spezifische Anwendungsfälle gibt, in denen Geld ein optimaler Typ wäre. Ich würde es nur verwenden, wenn es keinen sehr guten Anwendungsfall dafür gibt (z. B. wird die Spalte immer nur verwendet nach SUM aggregiert werden, große Mengen an Finanzdaten in großen Mengen laden).
Nathan Griffiths

@ TomTom es sind nicht nur die Genauigkeitsbeschränkungen. Die interne Darstellung kann ebenfalls Probleme verursachen. Geld ist ein praktischer Typ, um unwissende Entwickler zu fangen, kein großartiger Typ, den Entwickler missbrauchen. Das Mehrwertsteuerbeispiel sollte, unabhängig von den Regeln für die Berechnung, eindeutig nicht ignorante Entwickler abschrecken, wenn sie das Spezifische auf das Allgemeine anwenden.
Gerard ONeill

12

Als Gegenpol zur allgemeinen Ausrichtung der anderen Antworten. Sehen Sie die vielen Vorteile von Geld… Datentyp! im SQLCAT-Handbuch zur relationalen Engine

Insbesondere möchte ich auf Folgendes hinweisen

Bei der Implementierung von Kunden haben wir einige interessante Leistungszahlen für den Gelddatentyp gefunden. Wenn beispielsweise Analysis Services auf den Währungsdatentyp (von double) eingestellt wurde, um dem SQL Server-Gelddatentyp zu entsprechen, wurde die Verarbeitungsgeschwindigkeit (Zeilen / Sek.) Um 13% verbessert. Um eine schnellere Leistung in SQL Server Integration Services (SSIS) zu erzielen und 1,18 TB in weniger als 30 Minuten zu laden, wurde in SSIS 2008 - Weltrekord-ETL-Leistung festgestellt, dass die vier Dezimalspalten (9,2) mit einer Größe von geändert wurden 5 Bytes in der TPC-H LINEITEM-Tabelle zu Geld (8 Bytes) verbesserten die Geschwindigkeit beim Einfügen von Massen um 20% ... Der Grund für die Leistungsverbesserung liegt im TDS-Protokoll (Tabular Data Stream) von SQL Server. Das Prinzip des Schlüsselentwurfs besteht darin, Daten in kompakter binärer Form und so nah wie möglich am internen Speicherformat von SQL Server zu übertragen. Empirisch wurde dies während des SSIS 2008 - Weltrekord-ETL-Leistungstests mit Kernrate beobachtet; Das Protokoll fiel erheblich ab, als der Datentyp von Dezimal auf Geld umgestellt wurde. Dies macht die Datenübertragung so effizient wie möglich. Ein komplexer Datentyp benötigt zusätzliche Analyse- und CPU-Zyklen als ein Typ mit fester Breite.

Die Antwort auf die Frage lautet also "es kommt darauf an". Sie müssen bei bestimmten arithmetischen Operationen vorsichtiger sein, um die Präzision zu erhalten. Möglicherweise ist dies jedoch aufgrund von Leistungsaspekten sinnvoll.


Wie würden Sie dann Bitcoin speichern ?
Panagiotis Kanavos

@ PanagiotisKanavos - Ich habe keine Ahnung. Ich habe mich noch nie mit Bitcoin beschäftigt und weiß praktisch nichts darüber!
Martin Smith

6

Ich möchte eine andere Sicht auf GELD vs. NUMERISCH geben, die größtenteils auf meinem eigenen Fachwissen und meiner Erfahrung beruht ... Mein Standpunkt hier ist GELD, weil ich lange Zeit damit gearbeitet habe und NUMERISCH nie wirklich viel benutzt habe. .

GELD Pro:

  • Native Datentyp . Es verwendet einen nativen Datentyp ( Ganzzahl ) wie ein CPU-Register (32 oder 64 Bit), sodass für die Berechnung kein unnötiger Overhead erforderlich ist, sodass sie kleiner und schneller ist . GELD benötigt 8 Byte und NUMERICAL (19, 4) ) benötigt 9 Bytes (12,5% größer) ...

    GELD ist schneller, solange es verwendet wird (als Geld). Wie schnell? Mein einfacher SUMTest mit 1 Million Daten zeigt, dass GELD 275 ms und NUMERIC 517 ms beträgt ... Das ist fast doppelt so schnell ... Warum SUM-Test? Siehe nächster Pro- Punkt

  • Am besten für Geld . GELD eignet sich am besten zum Speichern von Geld und für Operationen, beispielsweise in der Buchhaltung. Ein einzelner Bericht kann nach Abschluss der SUM-Operation Millionen von Ergänzungen (SUM) und einige Multiplikationen ausführen. Für sehr große Buchhaltungsanwendungen ist es fast doppelt so schnell und äußerst bedeutsam ...
  • Geringe Geldpräzision . Geld im wirklichen Leben muss nicht sehr genau sein. Ich meine, viele Leute interessieren sich vielleicht für 1 Cent USD, aber wie wäre es mit 0,01 Cent USD? In meinem Land kümmern sich Banken nicht mehr um Cent (Ziffer nach Dezimalkomma). Ich weiß nichts über die US-Bank oder ein anderes Land ...

GELD Con:

  • Begrenzte Präzision . GELD hat nur eine Genauigkeit von vier Ziffern (nach dem Komma), daher muss es konvertiert werden, bevor Operationen wie Division ausgeführt werden ... Aber andererseits moneymuss es nicht so präzise sein und soll als Geld verwendet werden, nicht nur als a Nummer...

Aber ... Groß, aber hier ist sogar Ihre Anwendung mit echtem Geld verbunden, aber verwenden Sie sie nicht in vielen SUM-Operationen, wie in der Buchhaltung. Wenn Sie stattdessen viele Divisionen und Multiplikationen verwenden, sollten Sie kein GELD verwenden ...


1
Wenn Sie sagen wollen, dass Geld schneller als dezimal ist, müssen Sie uns beispielsweise mitteilen, welche rdbms, auf welcher Hardware, unter welchem ​​Betriebssystem, mit welchen spezifischen Daten welche spezifische Abfrage ausgeführt wird. Wenn es nicht VOLLSTÄNDIG korrekt ist, mache ich KEINE finanziellen Operationen damit, weil der Steuermann ziemlich unzufrieden sein wird, wenn er schlechte Zahlen zurückbekommt. Sie interessieren sich für den tausendsten Cent, wenn Sie zum Beispiel mit US-Währung zu tun haben. Wenn Geld das nicht tut, ist es nicht verwendbar.
Haakon Løtveit

3
@ HaakonLøtveit In diesem gesamten Q & A-Thread geht es um den SQL Server-Datentyp "Geld", daher denke ich nicht, dass sie dies in der Antwort angeben müssen. Geld kann unter bestimmten Umständen schneller als Dezimalzahlen verwendet werden (z. B. beim Laden von Daten). Weitere Informationen finden Sie in der Antwort von Martin Smith. Ich stimme der Mehrheit dieser Antwort darin zu, dass es bestimmte Anwendungsfälle gibt, die Money zu einer effizienteren Wahl als Dezimal machen können. Wenn es jedoch keinen sehr überzeugenden Fall für die Verwendung gibt, sollte dies meiner Meinung nach vermieden werden.
Nathan Griffiths

1
Bitcoin hat 8 Dezimalstellen. Sie können es nicht einmal in einer moneySpalte speichern
Panagiotis Kanavos

4

Alle vorherigen Beiträge bringen gültige Punkte, aber einige beantworten die Frage nicht genau.

Die Frage ist: Warum sollte jemand Geld bevorzugen, wenn wir bereits wissen, dass es sich um einen weniger genauen Datentyp handelt, der bei komplexen Berechnungen Fehler verursachen kann?

Sie verwenden Geld, wenn Sie keine komplexen Berechnungen durchführen und diese Präzision gegen andere Anforderungen eintauschen können.

Zum Beispiel, wenn Sie diese Berechnungen nicht durchführen müssen und Daten aus gültigen Währungstextzeichenfolgen importieren müssen. Diese automatische Konvertierung funktioniert nur mit dem Datentyp MONEY:

SELECT CONVERT(MONEY, '$1,000.68')

Ich weiß, dass Sie Ihre eigene Importroutine erstellen können. Manchmal möchten Sie jedoch keine Importroutine mit weltweit spezifischen Gebietsschemaformaten neu erstellen.

Ein weiteres Beispiel, wenn Sie diese Berechnungen nicht durchführen müssen (Sie müssen nur einen Wert speichern) und 1 Byte sparen müssen (Geld benötigt 8 Byte und Dezimalzahl (19,4) 9 Byte). In einigen Anwendungen (schnelle CPU, großer Arbeitsspeicher, langsame E / A), wie z. B. das Lesen großer Datenmengen, kann dies auch schneller sein.


2

Sie sollten kein Geld verwenden, wenn Sie Multiplikationen / Divisionen für den Wert durchführen müssen. Geld wird auf die gleiche Weise gespeichert wie eine Ganzzahl, während Dezimalstellen als Dezimalpunkt und Dezimalstellen gespeichert werden. Dies bedeutet, dass das Geld in den meisten Fällen an Genauigkeit verliert, während die Dezimalzahl dies nur tut, wenn sie wieder auf die ursprüngliche Skala zurückgesetzt wird. Geld ist ein Fixpunkt, daher ändert sich seine Skala während der Berechnungen nicht. Da es sich jedoch um einen festen Punkt handelt, wenn er als Dezimalzeichenfolge gedruckt wird (im Gegensatz zu einer festen Position in einer Zeichenfolge der Basis 2), werden Werte bis zur Skala von 4 genau dargestellt. Für Addition und Subtraktion ist Geld also in Ordnung.

Eine Dezimalstelle wird intern in der Basis 10 dargestellt, und daher basiert die Position des Dezimalpunkts auch auf der Basis 10-Zahl. Wodurch sein Bruchteil seinen Wert genau darstellt, genau wie bei Geld. Der Unterschied besteht darin, dass Zwischenwerte der Dezimalzahl eine Genauigkeit von bis zu 38 Stellen beibehalten können.

Bei einer Gleitkommazahl wird der Wert binär wie eine Ganzzahl gespeichert, und die Position des Dezimalpunkts (oder Binärpunkts) ist relativ zu den Bits, die die Zahl darstellen. Da es sich um einen binären Dezimalpunkt handelt, verlieren Basis-10-Zahlen direkt nach dem Dezimalpunkt an Genauigkeit. 1/5 oder 0,2 kann auf diese Weise nicht genau dargestellt werden. Weder Geld noch Dezimalstellen leiden unter dieser Einschränkung.

Es ist einfach genug, Geld in Dezimalzahlen umzuwandeln, die Berechnungen durchzuführen und den resultierenden Wert dann wieder in einem Geldfeld oder einer Geldvariablen zu speichern.

Von meinem POV möchte ich, dass Dinge, die mit Zahlen passieren, einfach passieren, ohne dass ich zu viel darüber nachdenken muss. Wenn alle Berechnungen in Dezimalzahlen konvertiert werden sollen, möchte ich für mich nur Dezimalzahlen verwenden. Ich würde das Geldfeld für Anzeigezwecke speichern.

In Bezug auf die Größe sehe ich nicht genug Unterschiede, um meine Meinung zu ändern. Geld benötigt 4 - 8 Bytes, während Dezimal 5, 9, 13 und 17 sein kann. Die 9 Bytes können den gesamten Bereich abdecken, den die 8 Bytes Geld können. Indexweise (Vergleichen und Suchen sollten vergleichbar sein).


Danke für das Upvote. Ich schaue mir das an und während ich verstehe, was ich sagen wollte, kann ich auch sehen, dass es sehr verwirrend ist. Vielleicht schreibe ich es später mit ein paar Beispielen gegen Dezimalstellen um.
Gerard ONeill

2

Ich habe einen Grund gefunden, Dezimal über Geld in Bezug auf Genauigkeit zu verwenden.

DECLARE @dOne   DECIMAL(19,4),
        @dThree DECIMAL(19,4),
        @mOne   MONEY,
        @mThree MONEY,
        @fOne   FLOAT,
        @fThree FLOAT

 SELECT @dOne   = 1,
        @dThree = 3,    
        @mOne   = 1,
        @mThree = 3,    
        @fOne   = 1,
        @fThree = 3

 SELECT (@dOne/@dThree)*@dThree AS DecimalResult,
        (@mOne/@mThree)*@mThree AS MoneyResult,
        (@fOne/@fThree)*@fThree AS FloatResult

DecimalResult> 1.000000

MoneyResult> 0,9999

FloatResult> 1

Testen Sie es einfach und treffen Sie Ihre Entscheidung.


2
Wir würden sehr gerne Ihre Schlussfolgerung hören (lesen, das heißt) .
Peter Mortensen

@PeterMortensen Ich denke, wenn ich Vollständigkeit und Genauigkeit zwischen Geld- und Dezimaltypen haben möchte, sollte meine Entscheidung Dezimal sein.
QMaster

1
Erwägen Sie, Ihre Antwort mit dem tatsächlichen Ergebnis der oben genannten zu aktualisieren. Dann wird Ihre Schlussfolgerung für jeden, der liest, sofort offensichtlich sein :-)
Agreax

1
@Ageax Das der Antwort hinzugefügte Ergebnis.
QMaster

1

Ich habe gerade diesen Blogeintrag gesehen: Money vs. Decimal in SQL Server .

Was im Grunde sagt, dass Geld ein Präzisionsproblem hat ...

declare @m money
declare @d decimal(9,2)

set @m = 19.34
set @d = 19.34

select (@m/1000)*1000
select (@d/1000)*1000

Für den moneyTyp erhalten Sie 19.30 statt 19.34. Ich bin nicht sicher, ob es ein Anwendungsszenario gibt, das Geld zur Berechnung in 1000 Teile aufteilt, aber dieses Beispiel weist einige Einschränkungen auf.


15
Es ist kein "Problem", sondern "gemäß Spezifikation": «Die Datentypen moneyund smallmoneysind auf ein Zehntausendstel der von ihnen repräsentierten Währungseinheiten genau.» wie gesagt in msdn.microsoft.com/en-us/library/ms179882.aspx weiß jeder, der "es ist Müll" sagt, nicht, wovon er spricht.
Albireo
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.