Dovresti scegliere i tipi di dati MONEY o DECIMAL (x, y) in SQL Server?


443

Sono curioso di sapere se esiste o meno una vera differenza tra il moneytipo di dati e qualcosa del genere decimal(19,4)(che è ciò che il denaro usa internamente, credo).

Sono consapevole che moneyè specifico di SQL Server. Voglio sapere se c'è un motivo valido per scegliere l'uno rispetto all'altro; la maggior parte degli esempi di SQL Server (ad esempio il database AdventureWorks) usa moneye non decimalper cose come le informazioni sui prezzi.

Devo solo continuare a utilizzare il tipo di dati in denaro, o c'è invece un vantaggio nell'uso del decimale? Il denaro è meno caratteri da digitare, ma questo non è un motivo valido :)


12
DECIMAL(19, 4) è una scelta popolare controlla questo controlla anche qui i formati di valuta del mondo per decidere quanti posti decimali usare, la speranza aiuta.
shaijut,

Mi chiedevo perché il tipo di dati in denaro abbia 4 decimali ... e non 2. vale a dire 100 centesimi in un dollaro, quindi sono necessari solo 2 decimali? Per archiviare un record di denaro inferiore a $ 9999,99, stavo andando con un tipo di dati decimale (6,2). Non mi preoccupo di dividere o moltiplicare i calcoli, solo la memorizzazione e la somma ...
Allan F

Risposte:


326

Mai e poi mai dovresti usare i soldi. Non è preciso ed è pura spazzatura; usa sempre decimale / numerico.

Esegui questo per vedere cosa intendo:

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

Uscita: 2949.0000 2949.8525

Ad alcune delle persone che hanno affermato di non dividere i soldi in soldi:

Ecco una delle mie domande per calcolare le correlazioni e cambiarla in denaro dà risultati sbagliati.

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

62
"Mai" è una parola forte. "Denaro" è utile per trasmettere i risultati a quel tipo per la visualizzazione per l'utente in modo sensibile alla cultura, ma hai ragione che è molto brutto da usare per i calcoli stessi.
Joel Coehoorn,

37
Il tuo esempio non è significativo, dal momento che nessuno potrà mai moltiplicare due oggetti di tipo denaro. Se vuoi dimostrare il tuo punto, devi confrontare la moltiplicazione di un denaro per un decimale con la moltiplicazione di un decimale per un decimale.
Brian,

27
.. ma è ancora sconcertante perché il denaro * non abbia la precisione del denaro.
Apprendimento del

4
@Learning: ha una precisione di denaro. Tuttavia, si verificano ancora errori di arrotondamento che possono accumularsi nel tempo. Il tipo decimale non usa l'aritmetica binaria: garantisce che ottiene gli stessi 10 risultati di base che si ottengono facendo su carta.
Joel Coehoorn,

56
Moltiplicazione e divisione di moneyoltre money, questa 'illustrazione' è manipolativa. È un fatto documentato che moneyha una precisione fissa e molto limitata. In tali casi si dovrebbe prima moltiplicare e poi dividere. Cambia l'ordine degli operatori in questo esempio e otterrai risultati identici. A moneyessenzialmente è un int a 64 bit, e se dovessi avere a che fare con ints, dovresti moltiplicarti prima di dividere.
Andriy M,

273

SQLMenace ha dichiarato che il denaro è inesatto. Ma non moltiplicare / dividere il denaro per denaro! Quanto costa 3 dollari volte 50 centesimi? 150 dollarcents? Moltiplica / dividi il denaro per gli scalari, che dovrebbero essere decimali.

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

Risultati nel risultato corretto:

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

moneyè valido finché non hai bisogno di più di 4 cifre decimali e ti assicuri che i tuoi scalari - che non rappresentano denaro - siano decimals.


57
quante monete da 1 centesimo può ottenere una banconota da un dollaro? una risposta a questo richiede denaro / denaro.
Apprendimento del

48
@Learning in quel caso il risultato non è denaro, ma un float. (Analisi dimensionale di base.)
Richard

11
@Learning: chiedi al database quanti centesimi in un dollaro molto? Comunque, ciò restituirebbe il risultato giusto. Il suo problema era che il denaro / denaro era preciso solo a quattro cifre (era 0,2949), quindi quando moltiplicato per 10000 divenne 2949.0000.
configuratore

26
@mson Ha ragione e non fare critiche personali come hai fatto sulla base di un'osservazione di una riga, non è utile. Se non si divide per $ 0,01 ma invece per 0,01, il risultato è $ 100 anziché 100. Ci sono 100 centesimi in un dollaro, non $ 100 centesimi. Le unità sono importanti! C'è sicuramente un grande posto per immergersi, e forse moltiplicare, denaro in denaro.
Andrewb,

19
Se voglio spendere $ 1000 per acquistare azioni al prezzo di $ 36, non è un uso legittimo di money / money? La risposta è intere unità senza il simbolo del dollaro attaccato, il che è corretto! Questo è uno scenario perfettamente ragionevole, che suggerisce che a causa di strani casi limite come questo, moneynon è un buon tipo di dati da usare, poiché il risultato viene sempre troncato per adattarsi moneyinvece di seguire le normali regole per precisione e scala. Cosa succede se si desidera calcolare la deviazione standard di un insieme di moneyvalori? Sì, Sqrt(Sum(money * money))(semplificato) in realtà ha senso.
ErikE,

59

Tutto è pericoloso se non sai cosa stai facendo

Anche i tipi decimali di alta precisione non possono salvare il giorno:

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

1.000000 <- Dovrebbe essere 0.6000000


I moneytipi sono numeri interi

Le rappresentazioni testuali di smallmoneye decimal(10,4)possono apparire simili, ma ciò non le rende intercambiabili. Cringe quando vedi le date memorizzate come varchar(10)? Questa è la stessa cosa.

Dietro le quinte, money/ smallmoneysono solo un bigint/ int Il punto decimale nella rappresentazione testuale di moneyè una lanugine visiva, proprio come i trattini in una data aaaa-mm-gg. SQL in realtà non li memorizza internamente.

Per quanto riguarda decimalvs money, scegli ciò che è appropriato per le tue esigenze. I moneytipi esistono perché la memorizzazione di valori contabili come multipli interi di 1/10000 di unità è molto comune. Inoltre, se hai a che fare con denaro e calcoli reali oltre alla semplice aggiunta e sottrazione, non dovresti farlo a livello di database! Fallo a livello di applicazione con una libreria che supporti Banker's Rounding (IEEE 754)


1
Puoi spiegare cosa è successo in questo esempio?
Sergey Popov,

4
Overflow della scala. A piccole scale, numerico (a, b) * numerico (c, d) produce numerico (a-b + c-d + 1, max (b, d)). Tuttavia, se (a + b + c + d)> 38, SQL limita la scala, rubando la precisione dal lato della frazione per riempire il lato intero, causando l'errore di arrotondamento.
Anon,

Tutti i calcoli numerici sono suscettibili di perdita di precisione a causa del ridimensionamento: calcola invece selezionare 1000000 * @ num1 * @ num2
Mitch Wheat

L'esempio di Anon è specifico per versione e database. ma il punto attenzione è valido. in sqlanywhere versione 1.1, l'esempio fornisce 0,600000 correttamente. (So ​​che stiamo parlando di ms sql qui). un altro punto sul tipo di denaro mancante da un altro database, ci sono modi che chiamano decimale o numerico come denaro, come la creazione del dominio.
gg89,

3
Penso che questa sia la risposta più illuminante perché hai spiegato non solo gli errori che si propagano, ma cosa sta realmente succedendo dietro la scena e perché SOLDI esiste in primo luogo. Non sono sicuro del motivo per cui ci sono voluti 4 anni per ottenere questa risposta, ma forse è perché c'è troppa attenzione al "problema" di calcolo, e non tanto sui perché e sui come di denaro rispetto ai decimali.
Steve Sether,

44

Mi rendo conto che WayneM ha affermato di sapere che i soldi sono specifici di SQL Server. Tuttavia, si sta chiedendo se ci sono ragioni per usare il denaro sopra il decimale o viceversa e penso che un motivo ovvio debba ancora essere dichiarato e che usare il decimale significa che è una cosa in meno di cui preoccuparsi se dovessi mai cambiare il tuo DBMS - che può succedere.

Rendi i tuoi sistemi il più flessibili possibile!


1
Forse, ma in teoria potresti dichiarare un dominio chiamato Money in un altro DBMS (che supporta la dichiarazione di domini).
dibattito

Dato che qualcuno sta attualmente convertendo un database SQL Server in Amazon Redshift, posso garantire che si tratta di un vero problema. Cerca di evitare tipi di dati personalizzati per una particolare piattaforma di database, a meno che non ci siano validi motivi commerciali per usarli.
Nathan Griffiths,

@Nathn ha dato il sistema di tipo debole di Redshift rispetto a PostgreSQL o SQL Server, ad esempio nessun datetipo, direi che avrai sempre tali problemi. Si dovrebbe dire "Non utilizzare tipi obsoleti quando il database fornisce già tipi migliori e più conformi agli standard e mette in guardia contro quelli obsoleti".
Panagiotis Kanavos,

@PanagiotisKanavos - il denaro non è deprecato
Martin Smith il

@MartinSmith è scioccato nel vederlo, in quanto non è in grado di gestire valori monetari come BTC nel 2017. O di distinguere tra importi in GBP e EUR, anche se si muovono verso la parità: P. Ad ogni modo, passare a Redshift introduce molto dolore
Panagiotis Kanavos,

32

Bene, mi piace MONEY! È un byte più economico di DECIMAL, e i calcoli eseguono più velocemente perché (sotto le copertine) le operazioni di addizione e sottrazione sono essenzialmente operazioni intere. L'esempio di @ SQLMenace — che è un grande avvertimento per gli ignari — potrebbe essere applicato ugualmente agli INTegers, dove il risultato sarebbe zero. Ma questo non è un motivo per non usare numeri interi, dove appropriato .

Quindi, è perfettamente 'sicuro' e appropriato da usare MONEYquando è quello che stai trattando MONEYe usarlo secondo le regole matematiche che segue (lo stesso di INTeger).

Sarebbe stato meglio se SQL Server avesse promosso la divisione e la moltiplicazione di MONEY's in DECIMALs (o FLOATs?) - possibilmente, ma non hanno scelto di farlo; né hanno scelto di promuovere INTegers FLOATquando li dividono.

MONEYnon ha problemi di precisione; che DECIMALs arrivare ad avere un tipo intermedio più grande utilizzato durante i calcoli è solo una 'possibilità' di utilizzare questo tipo (e non sono realmente sicuro quanto lontano che 'possibilità' si estende).

Per rispondere alla domanda specifica, un "motivo convincente"? Bene, se vuoi la massima performance assoluta in un SUM(x)dove xpotrebbe essere uno DECIMALo MONEY, allora MONEYavrai un vantaggio.

Inoltre, non dimenticare che è un cugino più piccolo, SMALLMONEYsolo 4 byte, ma raggiunge il limite massimo, 214,748.3647che è piuttosto piccolo per soldi, e quindi spesso non è adatto.

Per provare il punto attorno all'utilizzo di tipi intermedi più grandi, se si assegna l'intermedio in modo esplicito a una variabile, si verifica DECIMALlo stesso problema:

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

Produce 2950.0000(va bene, quindi almeno DECIMALarrotondato anziché MONEYtroncato, come farebbe un numero intero).


21
MONEYè un byte in meno di un grande DECIMAL , con una precisione massima di 19 cifre. Tuttavia, la maggior parte dei calcoli monetari del mondo reale (fino a $ 9,99 M) può rientrare in un DECIMAL(9, 2), che richiede solo cinque byte. Puoi risparmiare dimensioni, preoccuparti meno degli errori di arrotondamento e rendere il tuo codice più portatile.

Mentre @JonofAllTrades è corretto, è possibile anche recuperare le prestazioni dei numeri interi semplicemente usando un numero intero contenente centesimi o centesimi e salvare il byte aggiuntivo che codifica la posizione del punto decimale e che deve essere verificato quando si sommano i decimali.
dsz,

"Quindi, è perfettamente 'sicuro' e appropriato usare SOLDI quando quello che hai a che fare è SOLDI e usarlo secondo le regole matematiche che segue" -> tuttavia, vedi anche la risposta di Anon: "Tutto è pericoloso se non lo fai sai cosa stai facendo ". Non puoi mai prevedere in che modo le persone finiranno per interrogare il sistema che stai creando, meglio evitare la possibilità di un uso improprio quando è possibile. Il guadagno minuscolo nello stoccaggio non vale la pena IMHO.
Nathan Griffiths,

1
Prova a memorizzare un valore Bitcoin. Ha 8 decimali
Panagiotis Kanavos,

14

Abbiamo appena riscontrato un problema molto simile e ora sono un +1 per non usare mai Money se non nella presentazione di alto livello. Disponiamo di più tabelle (in effetti un buono di vendita e una fattura di vendita), ognuna delle quali contiene uno o più campi Denaro per motivi storici e dobbiamo eseguire un calcolo proporzionale per determinare la quantità di imposta sulla fattura totale pertinente per ogni riga sul buono di vendita. Il nostro calcolo è

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

Ciò si traduce in un calcolo denaro / denaro reale che provoca errori di scala sulla parte di divisione, che si moltiplica poi in una proporzione di iva errata. Quando questi valori vengono successivamente aggiunti, si finisce con una somma delle proporzioni IVA che non si sommano al valore totale della fattura. Se uno dei valori tra parentesi fosse un decimale (sto per lanciarne uno come tale) la proporzione IVA sarebbe corretta.

Quando in origine non esistevano le parentesi che prima funzionavano, suppongo che a causa dei valori più grandi coinvolti, simulasse effettivamente una scala superiore. Abbiamo aggiunto le parentesi perché stava eseguendo prima la moltiplicazione, che in alcuni rari casi aumentava la precisione disponibile per il calcolo, ma questo ha causato questo errore molto più comune.


8
Ma lo fa solo perché uno sviluppatore ignorante ha ignorato le regole per i calcoli dell'IVA e le limitazioni di precisione documentate del denaro.
TomTom,

1
@TomTom ma il punto che stai sollevando sulla possibilità di un uso improprio di questo tipo di dati è un argomento a favore dell'evitare di usarlo affatto.
Nathan Griffiths,

@Nathan No. Sto sottolineando che l'argomento dato come motivo per non usarlo mai è fondamentalmente uno sviluppatore incompetente, quindi l'argomento è falso.
TomTom

1
@TomTom purtroppo ci sono molti sviluppatori incompetenti (così come molti fantastici) e per me, a meno che non potessi garantire come questi dati sarebbero stati interrogati in futuro e nessuno avrebbe mai fatto il tipo di errori descritti qui , meglio errare dal lato della cautela e usare un tipo decimale. Detto questo, dopo aver letto tutte queste risposte, vedo che ci sono alcuni casi d'uso specifici in cui il denaro sarebbe un tipo ottimale da usare, semplicemente non lo userei a meno che non ci sia un ottimo caso d'uso (es. Colonna essere aggregato per SUM, caricamento in blocco di grandi quantità di dati finanziari).
Nathan Griffiths,

@ TomTom non sono solo i limiti di precisione. La rappresentazione interna può anche causare problemi. Il denaro è un tipo di convenienza per catturare sviluppatori ignoranti, non un grande tipo che gli sviluppatori stanno abusando. L'esempio iva, indipendentemente dalle regole per calcolarlo, dovrebbe chiaramente spaventare gli sviluppatori non ignoranti quando applicano lo specifico al generale.
Gerard ONeill,

12

Come contrappunto alla spinta generale delle altre risposte. Scopri i numerosi vantaggi del denaro ... Tipo di dati! nella Guida al motore relazionale di SQLCAT

In particolare, vorrei sottolineare quanto segue

Lavorando sulle implementazioni dei clienti, abbiamo trovato alcuni numeri di prestazioni interessanti riguardanti il ​​tipo di dati monetari. Ad esempio, quando Analysis Services è stato impostato sul tipo di dati di valuta (dal doppio) per corrispondere al tipo di dati di denaro di SQL Server, si è verificato un miglioramento del 13% nella velocità di elaborazione (righe / sec). Per ottenere prestazioni più rapide all'interno di SQL Server Integration Services (SSIS) per caricare 1,18 TB in meno di trenta minuti, come osservato in SSIS 2008 - prestazioni ETL record del mondo, è stato osservato che modificando le quattro colonne decimali (9,2) con una dimensione di 5 byte nella tabella TPC-H LINEITEM (8 byte) migliorano la velocità di inserimento in blocco del 20% ... Il motivo del miglioramento delle prestazioni è dovuto al protocollo Tabular Data Stream (TDS) di SQL Server, che ha il principio di progettazione chiave per trasferire i dati in formato binario compatto e il più vicino possibile al formato di archiviazione interno di SQL Server. Empiricamente, questo è stato osservato durante il SSIS 2008 - test delle prestazioni ETL da record mondiale usando Kernrate; il protocollo è diminuito in modo significativo quando il tipo di dati è passato da decimale a denaro. Ciò rende il trasferimento di dati il ​​più efficiente possibile. Un tipo di dati complesso richiede ulteriori cicli di analisi e CPU da gestire rispetto a un tipo a larghezza fissa.

Quindi la risposta alla domanda è "dipende". È necessario prestare maggiore attenzione con determinate operazioni aritmetiche per preservare la precisione, ma è possibile che le considerazioni sulle prestazioni lo rendano utile.


Come conserveresti bitcoin allora?
Panagiotis Kanavos,

@PanagiotisKanavos - Non ne ho idea. Non ho mai cercato bitcoin e non ne so praticamente nulla!
Martin Smith,

6

Voglio dare una visione diversa di DENARO rispetto a NUMERICO, in gran parte basato sulla mia competenza ed esperienza ... Il mio punto di vista qui è DENARO, perché ci ho lavorato per molto tempo e non ho mai usato molto NUMERICO molto .. .

SOLDI Pro:

  • Tipo di dati nativo . Utilizza un tipo di dati nativo ( intero ) uguale a un registro CPU (32 o 64 bit), quindi il calcolo non richiede un sovraccarico non necessario, quindi è più piccolo e più veloce ... DENARO ha bisogno di 8 byte e NUMERICO (19, 4 ) necessita di 9 byte (maggiore del 12,5%) ...

    SOLDI è più veloce fintanto che è usato per essere (come denaro). Quanto velocemente? Il mio semplice SUMtest su 1 milione di dati mostra che MONEY è 275 ms e NUMERIC 517 ms ... Questo è quasi due volte più veloce ... Perché SUM test? Vedi il prossimo punto Pro

  • Migliore per soldi . DENARO è il migliore per conservare denaro ed eseguire operazioni, ad esempio in contabilità. Un singolo report può eseguire milioni di aggiunte (SUM) e alcune moltiplicazioni al termine dell'operazione SUM. Per applicazioni di contabilità molto grandi è quasi il doppio della velocità ed è estremamente significativo ...
  • Bassa precisione del denaro . Il denaro nella vita reale non deve essere molto preciso. Voglio dire, a molte persone potrebbe interessare circa 1 centesimo di USD, ma che ne dite di 0,01 cent di USD? In effetti, nel mio paese, alle banche non interessano più i centesimi (cifra dopo virgola decimale); Non so della banca americana o di altri paesi ...

SOLDI Con:

  • Precisione limitata . DENARO ha solo quattro cifre (dopo la virgola) di precisione, quindi deve essere convertito prima di eseguire operazioni come la divisione ... Ma poi moneynon è necessario che sia così preciso ed è pensato per essere usato come denaro, non solo un numero...

Ma ... Grande, ma qui c'è anche la tua applicazione in denaro reale, ma non la usi in molte operazioni SUM, come in contabilità. Se invece usi molte divisioni e moltiplicazioni, non dovresti usare SOLDI ...


1
Se hai intenzione di dire che il denaro è più veloce del decimale, devi dirci cose come quale rdbms, su quale hardware, su quale sistema operativo, con quali dati specifici eseguono di quale query specifica stai parlando. Inoltre, se non è COMPLETAMENTE accurato, NON sto facendo alcuna operazione finanziaria con esso, perché il fisco sarà piuttosto scontento di ottenere numeri negativi. Ti preoccupi del millesimo centesimo, ad esempio se hai a che fare con la valuta americana. Se il denaro non lo fa, non è utilizzabile.
Haakon Løtveit,

3
@ HaakonLøtveit questo intero thread di domande e risposte riguarda il tipo di dati "soldi" di SQL Server, quindi non credo che debbano specificarlo nella risposta. Il denaro può essere più veloce da usare del decimale in alcune circostanze (ad es. Caricamento dei dati), vedere la risposta di Martin Smith per maggiori dettagli. Concordo con la maggior parte di questa risposta, in quanto vi sono alcuni casi d'uso che possono rendere Money una scelta più efficiente del decimale, tuttavia, a meno che non vi sia un caso molto convincente per utilizzarlo, penso che dovrebbe essere evitato.
Nathan Griffiths,

1
Bitcoin ha 8 decimali. Non puoi nemmeno memorizzarlo in una moneycolonna
Panagiotis Kanavos il

4

Tutti i post precedenti portano punti validi, ma alcuni non rispondono esattamente alla domanda.

La domanda è: perché qualcuno dovrebbe preferire il denaro quando sappiamo già che è un tipo di dati meno preciso e può causare errori se utilizzato in calcoli complessi?

Usi denaro quando non effettuerai calcoli complessi e puoi scambiare questa precisione con altre esigenze.

Ad esempio, quando non è necessario effettuare tali calcoli e è necessario importare dati da stringhe di testo in valuta valide. Questa conversione automatica funziona solo con il tipo di dati MONEY:

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

So che puoi creare la tua routine di importazione. Ma a volte non vuoi ricreare una routine di importazione con formati locali specifici in tutto il mondo.

Un altro esempio, quando non è necessario effettuare tali calcoli (è necessario solo memorizzare un valore) e è necessario salvare 1 byte (il denaro richiede 8 byte e il decimale (19,4) richiede 9 byte). In alcune applicazioni (CPU veloce, grande RAM, IO lento), come solo leggere una grande quantità di dati, anche questo può essere più veloce.


2

Non dovresti usare denaro quando devi fare moltiplicazioni / divisioni sul valore. Il denaro viene archiviato nello stesso modo in cui viene memorizzato un numero intero, mentre il decimale viene memorizzato come punto decimale e cifre decimali. Ciò significa che il denaro diminuirà la precisione nella maggior parte dei casi, mentre il decimale lo farà solo se convertito nuovamente nella sua scala originale. Il denaro è a virgola fissa, quindi la sua scala non cambia durante i calcoli. Tuttavia, poiché è un punto fisso quando viene stampato come stringa decimale (anziché come posizione fissa in una stringa di base 2), i valori fino alla scala 4 sono rappresentati esattamente. Quindi per addizione e sottrazione, il denaro va bene.

Un decimale è rappresentato internamente nella base 10 e quindi anche la posizione del punto decimale si basa sul numero della base 10. Il che rende la sua parte frazionaria rappresentare esattamente il suo valore, proprio come con il denaro. La differenza è che i valori intermedi dei decimali possono mantenere la precisione fino a 38 cifre.

Con un numero in virgola mobile, il valore viene memorizzato in binario come se fosse un numero intero e la posizione del punto decimale (o binario, ahem) è relativa ai bit che rappresentano il numero. Poiché si tratta di un punto decimale binario, i numeri di base 10 perdono precisione subito dopo il punto decimale. 1/5, o 0,2, non possono essere rappresentati esattamente in questo modo. Né il denaro né i decimali soffrono di questa limitazione.

È abbastanza facile convertire il denaro in decimale, eseguire i calcoli e quindi memorizzare il valore risultante in un campo di denaro o variabile.

Dal mio punto di vista, voglio che le cose che accadono ai numeri accadano solo senza doverci pensare troppo. Se tutti i calcoli verranno convertiti in decimali, allora per me vorrei solo usare i decimali. Salverei il campo di denaro a scopo di visualizzazione.

Per quanto riguarda le dimensioni, non vedo abbastanza differenza per cambiare idea. Il denaro impiega 4 - 8 byte, mentre il decimale può essere 5, 9, 13 e 17. I 9 byte possono coprire l'intero intervallo che gli 8 byte di denaro possono. Per quanto riguarda l'indice (il confronto e la ricerca dovrebbero essere comparabili).


Grazie per l'upgrade. Sto guardando questo e mentre ottengo quello che stavo cercando di dire, posso anche vedere che è molto confuso. Forse lo riscriverò più avanti con alcuni esempi decimali.
Gerard ONeill

2

Ho trovato una ragione sull'uso del decimale rispetto al denaro in materia di precisione.

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

Basta testarlo e prendere la tua decisione.


2
Ci piacerebbe molto conoscere (leggere, cioè) la tua conclusione.
Peter Mortensen,

@PeterMortensen Penso che se voglio avere completezza e accuratezza tra i tipi Money e Decimal, la mia decisione dovrebbe essere Decimale.
QMaster

1
Valuta di aggiornare la tua risposta con il risultato effettivo di quanto sopra. Quindi la tua conclusione sarà immediatamente ovvia per chiunque legga :-)
Agreax

1
@Ageax Il risultato è stato aggiunto alla risposta.
Q Master

1

Ho appena visto questo post nel blog: Money vs. Decimal in SQL Server .

Il che sostanzialmente dice che il denaro ha un problema di precisione ...

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

set @m = 19.34
set @d = 19.34

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

Per il moneytipo, otterrai 19.30 anziché 19.34. Non sono sicuro se esiste uno scenario applicativo che divide il denaro in 1000 parti per il calcolo, ma questo esempio espone alcune limitazioni.


15
Non è un "problema", è "secondo le specifiche": «I tipi di dati moneye smallmoneysono accurati per un decimilionesimo delle unità monetarie che rappresentano.» come detto in msdn.microsoft.com/en-us/library/ms179882.aspx, quindi chiunque dica "è spazzatura" non sa di cosa sta parlando.
Albireo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.