Il miglior tipo di dati per archiviare i valori monetari in MySQL


279

Voglio archiviare molti record in un database MySQL. Tutti contengono valori monetari. Ma non so quante cifre verranno inserite per ognuna.
Quale tipo di dati devo utilizzare per questo scopo?
VARCHAR o INT (o altri tipi di dati numerici)?


13
deimal(10,2)è quello che uso ... puoi regolare i valori in base alle dimensioni previste
Manse,

9
La domanda correlata è il miglior tipo di dati per la valuta ;).
shA.t

Risposte:


370

Poiché il denaro ha bisogno di una rappresentazione esatta, non utilizzare tipi di dati che sono solo approssimativi float. È possibile utilizzare un tipo di dati numerico a virgola fissa per tale like

decimal(15,2)
  • 15 è la precisione (lunghezza totale del valore comprese le cifre decimali)
  • 2 è il numero di cifre dopo il punto decimale

Vedi i tipi numerici MySQL :

Questi tipi vengono utilizzati quando è importante preservare la precisione esatta, ad esempio con i dati monetari .


3
quale potrebbe essere la differenza tra il tipo di dati decimale e numerico per questo caso?
Emilio Gort,

60
In MySQL decimale numericsono gli stessi.
juergen d

21
Uso personalmente numeric(19,4)per i registri finanziari che ti danno una mano migliore per giocare e adottare facilmente nuove richieste.
YahyaE,

10
Sono d'accordo con YahyaE, più decimali è meglio. Ci sono alcune valute che in genere usano 3 cifre decimali, come il Bahrein, il giordano o il dinaro kuwaitiano, quindi ne hai bisogno almeno 3. Quattro o cinque sono migliori.
Edwin Hoogerbeets,

1
@EdwinHoogerbeets Non essendo un contabile ... ma gestendo un piccolo biz nel Regno Unito ... Ricordo di aver letto da qualche parte molto tempo fa che le cifre delle valute dovevano essere memorizzate in 4 decimali anche per £, $, ecc. In modo che alcuni calcoli potessero utilizza effettivamente gli ultimi 2 decimali per alcuni contesti contabili oscuri. Wd ha bisogno di un commercialista per confermare / confutare.
mike rodent,

88

Puoi usare DECIMALo NUMERICentrambi sono uguali

I tipi DECIMAL e NUMERIC memorizzano valori esatti di dati numerici. Questi tipi vengono utilizzati quando è importante preservare la precisione esatta, ad esempio con i dati monetari. In MySQL, NUMERIC è implementato come DECIMAL, quindi le seguenti osservazioni su DECIMAL si applicano ugualmente a NUMERIC. : MySQL

vale a dire DECIMAL(10,2)

Impostazioni di esempio

Buona lettura


3
Forse confuso, ma lo screenshot non corrisponde al testo della risposta (precisione, scala).
Patrick Hofman,

Sto usando il decimale (10,2) per il mio valore in denaro, tuttavia quando metto qualcosa come 867.000,00 viene salvato come 867. Cosa sto facendo di sbagliato?
codeinprogress

32

Preferisco usare BIGINTe memorizzare i valori moltiplicandoli per 100 , in modo che diventino numeri interi.

Ad esempio, per rappresentare un valore in valuta di 93.49, il valore deve essere memorizzato come 9349, mentre viene visualizzato il valore che possiamo dividere per 100 e visualizzare. Questo occuperà meno spazio di archiviazione.

Attenzione: per lo
più non eseguiamo la currency * currencymoltiplicazione, nel caso in cui lo stiamo facendo quindi dividere il risultato con 100 e memorizzare, in modo che ritorni alla precisione corretta.


Ricordo di aver detto una cosa simile da un professore nel mio corso universitario di Computer Systems. Mi è stato insegnato che il modo più preciso è quello di memorizzare in centesimi (o cent) moltiplicando per 100 e salvando come intero e dividendo per 100 per visualizzarlo all'utente. Immagino che questo abbia benefici in termini di accuratezza e prestazioni del sistema di database.
LondonAppDev,

11
Qual è il vantaggio rispetto DECIMAL? Crei la necessità di tradurre centesimi in dollari e guai se lo dimentichi ad un certo punto.

1
Lo spazio è l'unico vantaggio, ma sì, dobbiamo stare più attenti quando utilizziamo questa funzione.
Dinesh PR,

4
Nel caso in cui non sia ovvio: diffidare dall'uso del metodo di rimozione della bilancia se si memorizza denaro in centesimi frazionari (ad esempio, $0.005o $0.12345) perché non si ridurrà a un numero intero dopo aver moltiplicato per 100. Se si conosce la precisione dei valori è chiaro che la migliore opzione è usare DECIMAL. Ma se non conosci la precisione (come nei miei esempi), allora ... sarebbe FLOATappropriato?
Quinn Comendant,

1
Un vantaggio di questo metodo viene quando si utilizza un linguaggio come JavaScript che utilizza IEEE-754 per memorizzare numeri in virgola mobile. Questa specifica non garantisce che 0,1 + 0,2 === 0,3 sia vero. La memorizzazione della valuta come numero intero dà la certezza che l'applicazione non subirà questo tipo di errore. Questa potrebbe non essere la soluzione migliore però. Sono arrivato a questa pagina mentre cercavo soluzioni e non ho ancora finito.
Gary Ott,

27

Dipende dalle tue necessità.

L'uso di DECIMAL(10,2)solito è sufficiente, ma se hai bisogno di valori un po 'più precisi puoi impostare DECIMAL(10,4).

Se lavori con valori elevati sostituisci 10con 19.


Sto usando il decimale (10,2) per il mio valore in denaro, tuttavia quando metto qualcosa come 867.000,00 viene salvato come 867. Cosa sto facendo di sbagliato?
codeinprogress

2
@codeinprogress Usi il separatore locale / decimale errato?
David Balažic,

15

Se l'applicazione deve gestire valori monetari fino a un trilione, questo dovrebbe funzionare: 13,2 Se è necessario rispettare i principi contabili generalmente accettati, utilizzare: 13,4

Di solito dovresti sommare i valori del tuo denaro a 13,4 prima di arrotondare l'output a 13,2.


5
Se hai intenzione di prendere Bitcoin, avrai bisogno di 8 cifre decimali, anche se la maggior parte dei portafogli va su mBTC che è 3 en.wikipedia.org/wiki/Bitcoin
Christian

Non pensare che questa risposta sia vera. opendata.stackexchange.com/a/10348/13983 @ david.ee ottenuto una fonte per questo?
Evan Carroll,

@EvanCarroll fammi rispondere per david.ee. Penso che questo articolo possa essere la fonte rietta.com/blog/2012/03/03/best-data-types-for-currencymoney-in
naXa

@naXa il link non cita nulla di qualsiasi fonte che supporti la pretesa di usare 13,4 per GAAP. Tutto quello che hai fatto è stato il collegamento a un articolo che fa la stessa affermazione non comprovata.
iheanyi,

6

In effetti, ciò si basa sulle preferenze del programmatore. Personalmente utilizzo: numeric(15,4)per conformarmi ai Principi contabili generalmente accettati ( GAAP ) .


5
Non ha nulla a che fare con le "preferenze del programmatore" o con ciò che "usi personalmente". È dettato dal dominio problematico, che richiede una radice decimale. Non è una questione in cui il programmatore può esercitare le proprie preferenze personali.
Marchese di Lorne,

3

Prova a usare

Decimal(19,4)

questo di solito funziona anche con tutti gli altri DB


3

Usiamo double.

* Gasp *

Perché?

Perché può rappresentare qualsiasi numero di 15 cifre senza vincoli sulla posizione del punto decimale . Tutto per un misero 8 byte!

Quindi può rappresentare:

  • 0.123456789012345
  • 123456789012345.0

... e qualsiasi altra via di mezzo.

Questo è utile perché abbiamo a che fare con valute globali edouble possiamo memorizzare i vari numeri di posizioni decimali che probabilmente incontreremo.

Un singolo doublecampo può rappresentare 999.999.999.999.999 in yen giapponesi, 9.999.999.999.999,99 in dollari USA e persino 9.999.999.9999999 in bitcoin

Se si tenta di fare lo stesso con decimal, è necessariodecimal(30, 15) che costa 14 byte.

Avvertenze

Certo, usando double non è privo di avvertenze.

Tuttavia, non è una perdita di precisione come alcuni tendono a sottolineare. Anche se doublepotrebbe non essere esatto internamente al sistema base 10 , possiamo renderlo esatto arrotondando il valore che estraiamo dal database ai suoi decimali significativi. Se necessario, lo è. (es. se verrà emesso, ed è richiesta la rappresentazione di base 10).

Le avvertenze sono, ogni volta che eseguiamo l'aritmetica con esso, dobbiamo normalizzare il risultato (arrotondandolo alle sue decimali significative) prima di:

  1. Eseguendo confronti su di esso.
  2. Riscrivendolo nel database.

Un altro tipo di avvertimento è, a differenza di decimal(m, d)dove il database impedirà ai programmi di inserire un numero con più di mcifre, non esistono convalide di questo tipo double. Un programma potrebbe inserire un valore immesso dall'utente di 20 cifre e finirà per essere silenziosamente registrato come un importo impreciso.


La prima volta che ho visto una risposta come questa, interessante. D: Se scrivo un float come 1.41 nel database e per qualche motivo devo moltiplicarlo per un numero enorme in mysql, come 1.000.000.000.000. Il risultato arrotondato sarà esattamente: 1.410.000.000.000?
roelleor,

@roelleor Perché il risultato sia esattamente 1.410.000.000.000 (virgola come separatore delle migliaia) si presume che l'input sia 1.410000000000(dodici cifre decimali significative), ma moltiplicandolo per 1.000.000.000.000 (ovvero 13 cifre significative rimaste del punto decimale) significa che stiamo lavorando con almeno un combinato di 25 cifre di significato. Questo supera di gran lunga i 15 disponibili per un doppio, quindi dal punto di vista del design penso che sarebbe molto rotto.
antak,

2

Al momento questa domanda è stata posta nessuno pensava al prezzo di Bitcoin. Nel caso di BTC, probabilmente non è sufficiente da usare DECIMAL(15,2). Se il Bitcoin salirà a $ 100.000 o più, avremo almeno bisogno DECIMAL(18,9)di supportare criptovalute nelle nostre app.

DECIMAL(18,9)occupa 12 byte di spazio in MySQL ( 4 byte per 9 cifre ).


> Un bitcoin può essere diviso in 8 cifre decimali. Pertanto, 0,00000001 BTC è l'importo minimo che può essere gestito in una transazione. Penso che intendi 8 invece di 9?
danger89,

1
Lo so, ma 9 occupa lo stesso spazio su disco di 8. Dai documenti MySQL: "I valori per le colonne DECIMAL sono memorizzati usando un formato binario che racchiude nove cifre decimali in 4 byte"
bizwiz

Scusa, ora ti capisco. Grazie.
danger89,

2

Conservare il denaro BIGINTmoltiplicato per 100 o più con il motivo di utilizzare meno spazio di archiviazione non ha senso in tutte le situazioni "normali".



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.