552 Stimmen

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

Ich bin neugierig, ob es einen wirklichen Unterschied gibt zwischen dem money Datentyp und etwas wie decimal(19,4) (das ist das, was Geld intern verwendet, glaube ich).

Ich bin mir bewusst, dass money ist spezifisch für SQL Server. Ich möchte wissen, ob es einen zwingenden Grund gibt, das eine dem anderen vorzuziehen; die meisten SQL Server-Beispiele (z. B. die AdventureWorks-Datenbank) verwenden money でなく decimal für Dinge wie Preisinformationen.

Sollte ich einfach weiterhin den Datentyp "Geld" verwenden, oder gibt es einen Vorteil, wenn ich stattdessen "Dezimal" verwende? Bei Geld sind weniger Zeichen einzugeben, aber das ist kein triftiger Grund :)

22 Stimmen

DECIMAL(19, 4) ist eine beliebte Wahl siehe este Prüfen Sie auch ici Weltwährungsformate, um zu entscheiden, wie viele Dezimalstellen zu verwenden sind, hoffentlich hilft das.

0 Stimmen

Ich habe mich gefragt, warum der Gelddatentyp 4 Dezimalstellen hat und nicht 2. z.B. 100 Cent in einem Dollar, so dass nur 2 Dezimalstellen erforderlich sind? Um einen Datensatz mit Geldbeträgen unter 9999,99 $ zu speichern, wollte ich einen Datentyp mit dem Wert decimal(6,2) verwenden. Ich bin nicht besorgt über dividieren oder multiplizieren Berechnungen, nur die Speicherung und Summierung

1 Stimmen

Einige Währungen sind in kleinere Teile als Hunderter unterteilt, z.B. ist der bahrainische Dinar in 1000 Fils unterteilt

414voto

SQLMenace Punkte 128184

Niemals sollten Sie Geld verwenden. Es ist ungenau und 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

Leistung: 2949.0000 2949.8525

An einige der Leute, die sagten, dass man Geld nicht durch Geld teilt:

Hier ist eine meiner Abfragen zur Berechnung von Korrelationen, und die Änderung in Geld ergibt falsche Ergebnisse.

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

85 Stimmen

"Nie" ist ein starkes Wort. "Geld" ist nützlich, um Ergebnisse in diesen Typ umzuwandeln, damit sie dem Benutzer auf kultursensible Weise angezeigt werden können, aber Sie haben Recht, dass es für die Berechnungen selbst sehr schlecht ist.

46 Stimmen

Ihr Beispiel ist nicht aussagekräftig, denn niemand wird jemals zwei Objekte vom Typ Geld multiplizieren. Wenn Sie Ihren Standpunkt beweisen wollen, müssen Sie die Multiplikation eines Geldes mit einer Dezimalzahl mit der Multiplikation einer Dezimalzahl mit einer Dezimalzahl vergleichen.

1 Stimmen

Ich glaube nicht, dass es einen Fall gibt, in dem Geld mit Geld multipliziert wird; Geld mit int oder Geld mit float vielleicht.

309voto

configurator Punkte 39516

SQLMenace sagte, dass Geld ungenau ist. Aber man multipliziert/dividiert Geld nicht mit Geld! Wie viel ist 3 Dollar mal 50 Cent? 150 Dollarcents? 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

Ergibt das richtige Ergebnis:

moneyresult           numericresult
--------------------- ---------------------------------------
2949.8525             2949.8525

money ist gut, solange Sie nicht mehr als 4 Dezimalstellen benötigen und sicherstellen, dass Ihre Skalare - die kein Geld darstellen - decimal s.

71 Stimmen

Wie viele 1-Cent-Münzen kann man für einen Dollarschein bekommen? Für eine Antwort auf diese Frage braucht man Geld.

0 Stimmen

Ich habe eine Korrelationsabfrage zu meiner Antwort hinzugefügt, die ich für die monatliche Leistung ausführe. Was würde passieren, wenn ich den Datentyp "Geld" verwenden würde?

58 Stimmen

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

93voto

Anon Punkte 10144

Alles ist gefährlich, wenn man nicht weiß, was man tut

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


Le site money Typen sind ganze Zahlen

Die Textdarstellungen von smallmoney y decimal(10,4) sehen zwar ähnlich aus, aber das macht sie nicht austauschbar. Erschrecken Sie auch, wenn Sie Daten sehen, die als varchar(10) ? Das ist das Gleiche.

Hinter den Kulissen, money / smallmoney sind nur ein bigint / int Das Dezimalkomma in der Textdarstellung von money ist ein visueller Schnickschnack, genau wie die Bindestriche in einem JJJJ-MMT-Datum. SQL speichert diese intern nicht.

Betreffend decimal gegen money Wählen Sie, was für Ihre Bedürfnisse geeignet ist. Die money Typen gibt es, weil die Speicherung von Buchhaltungswerten als ganzzahlige Vielfache von 1/10000stel der Einheit sehr üblich ist. Auch wenn Sie mit echtem Geld und Berechnungen jenseits von einfacher Addition und Subtraktion zu tun haben, Sie sollten das nicht auf der Datenbankebene tun! Tun Sie es auf der Anwendungsebene mit einer Bibliothek, die Folgendes unterstützt Banker's Rounding (IEEE 754)

1 Stimmen

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

7 Stimmen

Skalenüberlauf. Bei kleinen Skalen ergibt numeric(a,b) * numeric(c,d) numeric(a-b+c-d+1, max(b,d)). Wenn jedoch (a+b+c+d)>38 ist, kappt SQL die Skala und raubt der Bruchseite Präzision, um die Ganzzahlseite aufzufüllen, was den Rundungsfehler verursacht.

0 Stimmen

Alle numerischen Berechnungen sind anfällig für Präzisionsverluste aufgrund von Skalierung: Berechnen Sie stattdessen select 1000000 * @ num1 * @ num2

47voto

Dean Punkte 4446

Ich weiß, 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 statt Dezimalzahlen zu verwenden oder umgekehrt, und ich denke, dass ein offensichtlicher Grund noch genannt werden sollte, und zwar, dass die Verwendung von Dezimalzahlen bedeutet, dass man sich weniger Sorgen machen muss, wenn man jemals sein DBMS ändern muss - was passieren kann.

Machen Sie Ihre Systeme so flexibel wie möglich!

2 Stimmen

Möglicherweise, aber theoretisch könnten Sie eine Domäne namens Money in einem anderen DBMS deklarieren (das die Deklaration von Domänen unterstützt).

2 Stimmen

Als jemand, der derzeit eine SQL Server-Datenbank zu Amazon Redshift konvertiert, kann ich bestätigen, dass dies ein echtes Problem ist. Versuchen Sie, Datentypen zu vermeiden, die auf eine bestimmte Datenbankplattform zugeschnitten sind, es sei denn, es gibt sehr gute geschäftliche Gründe, sie zu verwenden.

0 Stimmen

@Nathn angesichts des schwachen Typensystems von Redshift im Vergleich zu PostgreSQL oder SQL Server, z. B. keine date Typ, würde ich sagen, Sie werden immer haben solche Probleme. Sie sollten sagen: "Verwenden Sie keine veralteten Typen, wenn die Datenbank bereits bessere, standardkonformere Typen anbietet und warnt gegen die abgelehnten".

34voto

dsz Punkte 3890

Nun, ich mag MONEY ! Es ist um ein Haar billiger als DECIMAL und die Berechnungen werden schneller ausgeführt, weil (unter der Haube) Additions- und Subtraktionsoperationen im Wesentlichen Ganzzahloperationen sind. Das Beispiel von @SQLMenace - das eine großartige Warnung für die Unwissenden ist - könnte auch angewendet werden auf INT egers, bei denen das Ergebnis gleich Null wäre. Aber das ist kein Grund, keine ganzen Zahlen zu verwenden. wo angemessen .

Es ist also vollkommen "sicher" und angemessen, die MONEY wenn man es mit folgenden Dingen zu tun hat MONEY und verwenden es nach mathematischen Regeln, die es befolgt (genauso wie INT eger).

Wäre es besser gewesen, wenn SQL Server die Division und Multiplikation von MONEY in DECIMAL s (oder FLOAT Möglicherweise, aber sie haben sich nicht dafür entschieden; und sie haben sich auch nicht dafür entschieden, die INT egers zu FLOAT s, wenn sie geteilt werden.

MONEY kein Problem mit der Genauigkeit hat; dass DECIMAL Die Möglichkeit, einen größeren Zwischentyp bei Berechnungen zu verwenden, ist nur ein "Merkmal" der Verwendung dieses Typs (und ich bin mir nicht sicher, wie weit dieses "Merkmal" reicht).

Um die konkrete Frage zu beantworten: ein "zwingender Grund"? Nun, wenn Sie ein absolutes Maximum an Leistung in einem SUM(x) donde x könnte entweder sein DECIMAL o MONEY entonces MONEY einen Vorteil haben wird.

Vergessen Sie auch nicht seinen kleineren Cousin, SMALLMONEY -nur 4 Bytes, aber der Höchstwert liegt bei 214,748.3647 - die für das Geld ziemlich klein ist und daher oft nicht gut passt.

Um zu beweisen, dass die Verwendung größerer Zwischentypen sinnvoll ist, weisen Sie das Zwischenprodukt explizit einer Variablen zu, DECIMAL leidet unter demselben Problem:

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 DECIMAL eher abgerundet als MONEY abgeschnitten - wie bei einer ganzen Zahl).

22 Stimmen

MONEY ist ein Byte weniger als ein groß DECIMAL mit einer Genauigkeit von bis zu 19 Ziffern. Die meisten realen Geldberechnungen (bis zu 9,99 Mio. $) passen jedoch in eine DECIMAL(9, 2) die nur fünf Bytes benötigt. Sie können Größe sparen und müssen sich weniger Sorgen über Rundungsfehler machen, y Ihren Code portabler zu machen.

0 Stimmen

Auch wenn @JonofAllTrades recht hat, könnte man die Leistung von Ganzzahlen auch zurückgewinnen, indem man einfach eine Ganzzahl verwendet, die Pennies oder Cents enthält, und das zusätzliche Byte einspart, das die Position des Dezimalpunkts kodiert und das beim Addieren von Dezimalzahlen überprüft werden muss.

0 Stimmen

"Es ist also vollkommen 'sicher' und angemessen, GELD zu verwenden, wenn man es mit GELD zu tun hat und es nach mathematischen Regeln verwendet, denen es folgt" -> siehe aber auch die Antwort von Anon: "Alles ist gefährlich, wenn man nicht weiß, was man tut". Man kann nie vorhersagen, wie die Leute das von einem geschaffene System am Ende abfragen werden, am besten vermeidet man die Möglichkeit des Missbrauchs, wenn man kann. Der geringfügige Gewinn an Speicherplatz ist es IMHO nicht wert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X