Meilleur type de données pour stocker des valeurs monétaires dans MySQL


279

Je souhaite stocker de nombreux enregistrements dans une base de données MySQL. Tous contiennent des valeurs monétaires. Mais je ne sais pas combien de chiffres seront insérés pour chacun.
Quel type de données dois-je utiliser à cet effet?
VARCHAR ou INT (ou d'autres types de données numériques)?


13
deimal(10,2)est ce que j'utilise ... vous pouvez ajuster les valeurs en fonction de la taille attendue
Manse

9
La question connexe est le meilleur type de données pour la devise ;).
shA.t

Réponses:


370

Étant donné que l'argent a besoin d'une représentation exacte, n'utilisez pas de types de données qui ne sont qu'approximatifs float. Vous pouvez utiliser un type de données numérique à virgule fixe pour cela comme

decimal(15,2)
  • 15 est la précision (longueur totale de la valeur, y compris les décimales)
  • 2 est le nombre de chiffres après le point décimal

Voir Types numériques MySQL :

Ces types sont utilisés lorsqu'il est important de conserver une précision exacte, par exemple avec des données monétaires .


3
quelle pourrait être la différence entre le type de données décimal et numérique pour ce cas?
Emilio Gort

60
Dans MySQL decimalet numericsont les mêmes.
juergen d

21
Je l'utilise personnellement numeric(19,4)pour les dossiers financiers qui vous donne une meilleure main pour jouer et adopter facilement de nouvelles demandes.
YahyaE

10
Je suis d'accord avec YahyaE, plus de décimales c'est mieux. Certaines devises utilisent généralement 3 décimales, comme les dinars bahreïni, jordanien ou koweïtien, vous en avez donc besoin d'au moins 3. Quatre ou cinq, c'est mieux.
Edwin Hoogerbeets

1
@EdwinHoogerbeets N'étant pas comptable ... mais gérant un petit commerce au Royaume-Uni ... Je me souviens avoir lu quelque part il y a longtemps que les chiffres des devises devraient être stockés à 4 décimales même pour £, $, etc. afin que certains calculs puissent utilise en fait les 2 dernières décimales pour certains contextes comptables obscurs. Nous avons besoin d'un comptable pour confirmer / réfuter.
mike rodent

88

Vous pouvez utiliser DECIMALou les NUMERICdeux sont identiques

Les types DECIMAL et NUMERIC stockent des valeurs de données numériques exactes. Ces types sont utilisés lorsqu'il est important de conserver une précision exacte, par exemple avec des données monétaires. Dans MySQL, NUMERIC est implémenté en tant que DECIMAL, donc les remarques suivantes sur DECIMAL s'appliquent également à NUMERIC. : MySQL

c'est à dire DECIMAL(10,2)

Exemples de paramètres

Bonne lecture


3
Peut-être déroutant, mais votre capture d'écran ne correspond pas à votre texte de réponse (précision, échelle).
Patrick Hofman

J'utilise décimal (10,2) pour ma valeur monétaire, mais lorsque je mets quelque chose comme 867 000,00, il est enregistré sous 867. que fais-je de mal?
codeinprogress

32

Je préfère utiliser BIGINTet stocker les valeurs en multipliant par 100 , afin qu'il devienne entier.

Par exemple, pour représenter une valeur monétaire de 93.49, la valeur doit être stockée sous la forme 9349, tout en affichant la valeur que nous pouvons diviser par 100 et afficher. Cela occupera moins d'espace de stockage.

Attention:
Généralement, nous n'effectuons pas de currency * currencymultiplication, au cas où si nous le faisions, divisez le résultat par 100 et stockez-le, afin qu'il revienne à la bonne précision.


Je me souviens avoir entendu une chose similaire par un professeur lors de mon cours universitaire en informatique. On m'a appris que le moyen le plus précis est de stocker en centimes (ou cent) par multiplier par 100 et enregistrer en tant que nombre entier et en divisant par 100 pour l'afficher à l'utilisateur. Je suppose que cela présente des avantages en termes de précision et de performances du système de base de données.
LondonAppDev

11
Quel est l'avantage DECIMAL? Vous créez un besoin de convertir des sous en dollars, et malheur si vous l'oubliez à un moment donné.

1
L'espace est le seul avantage, mais oui, nous devons être plus prudents lorsque nous utilisons cette fonctionnalité.
Dinesh PR

4
Dans le cas où ce n'est pas évident: méfiez-vous de l'utilisation de la méthode de suppression d'échelle si vous stockez de l'argent en cents fractionnaires (par exemple, $0.005ou $0.12345) car ils ne se réduiront pas à un entier après avoir été multipliés par 100. Si vous connaissez la précision des valeurs, il est clair que la meilleure option est d'utiliser DECIMAL. Mais si vous ne connaissez pas la précision (comme dans mes exemples), alors… serait FLOATapproprié?
Quinn Comendant du

1
Un avantage de cette méthode vient de l'utilisation d'un langage comme JavaScript qui utilise IEEE-754 pour stocker des nombres à virgule flottante. Cette spécification ne garantit pas que 0,1 + 0,2 === 0,3 est vrai. Le stockage de la devise sous forme d'entier garantit que votre application ne subira pas ce type d'erreur. Ce n'est peut-être pas la meilleure solution. Je suis arrivé sur cette page en recherchant des solutions et je n'ai pas encore fini.
Gary Ott

27

Cela dépend de vos besoins.

Utiliser DECIMAL(10,2)habituellement suffit mais si vous avez besoin de valeurs un peu plus précises, vous pouvez les définir DECIMAL(10,4).

Si vous travaillez avec de grandes valeurs, remplacez 10par 19.


J'utilise décimal (10,2) pour ma valeur monétaire, mais lorsque je mets quelque chose comme 867 000,00, il est enregistré sous 867. que fais-je de mal?
codeinprogress

2
@codeinprogress Vous utilisez le mauvais séparateur local / décimal?
David Balažic

15

Si votre application doit gérer des valeurs monétaires pouvant atteindre un billion, cela devrait fonctionner: 13,2 Si vous devez vous conformer aux PCGR (principes comptables généralement reconnus), utilisez: 13,4

Habituellement, vous devez additionner vos valeurs monétaires à 13,4 avant d'arrondir la sortie à 13,2.


5
Si vous allez prendre Bitcoin, vous aurez besoin de 8 décimales, bien que la plupart des portefeuilles soient vers mBTC qui est 3 fr.wikipedia.org/wiki/Bitcoin
Christian

Ne pensez pas que cette réponse est vraie. opendata.stackexchange.com/a/10348/13983 @ david.ee a une source pour ça?
Evan Carroll

@EvanCarroll laissez-moi répondre pour david.ee. Je pense que cet article peut être la source rietta.com/blog/2012/03/03/best-data-types-for-currencymoney-in
naXa

@naXa, le lien ne cite rien provenant d'aucune source soutenant la prétention d'utiliser 13,4 pour les PCGR. Tout ce que vous avez fait était de créer un lien vers un article qui fait la même affirmation sans fondement.
iheanyi

6

En effet, cela dépend des préférences du programmeur. J'utilise personnellement: numeric(15,4)pour se conformer aux principes comptables généralement reconnus ( PCGR ) .


5
Cela n'a rien à voir avec les «préférences du programmeur» ou ce que vous «utilisez personnellement». Il est dicté par le domaine problématique, qui nécessite une radix décimale. Ce n'est pas une question dans laquelle le programmeur peut exercer ses propres préférences personnelles.
Marquis de Lorne

3

Essayez d'utiliser

Decimal(19,4)

cela fonctionne généralement avec tous les autres DB aussi


3

Nous utilisons double.

*haleter*

Pourquoi?

Parce qu'il peut représenter n'importe quel nombre à 15 chiffres sans aucune contrainte sur l'emplacement du point décimal . Le tout pour un maigre 8 octets!

Il peut donc représenter:

  • 0.123456789012345
  • 123456789012345.0

... et quoi que ce soit entre les deux.

Ceci est utile car nous avons affaire à des devises mondiales et doublepeut stocker les différents nombres de décimales que nous rencontrerons probablement.

Un seul doublechamp peut représenter 999 999 999 999 999 s en yens japonais, 9 999 999 999 999,99 s en dollars américains et même 9 999 999 99999 99999 s en bitcoins

Si vous essayez de faire de même avec decimal, vous avez besoin de decimal(30, 15)ce qui coûte 14 octets.

Avertissements

Bien sûr, l'utilisation doublen'est pas sans réserves.

Cependant, ce n'est pas une perte de précision comme certains ont tendance à le souligner. Même si doublelui-même peut ne pas être exact en interne pour le système de base 10 , nous pouvons le rendre exact en arrondissant la valeur que nous tirons de la base de données à ses décimales significatives. Si besoin est. (Par exemple, s'il doit être sorti et qu'une représentation en base 10 est requise.)

Les mises en garde sont, chaque fois que nous effectuons de l'arithmétique avec lui, nous devons normaliser le résultat (en l'arrondissant à ses décimales significatives) avant:

  1. Effectuer des comparaisons dessus.
  2. Le réécrire dans la base de données.

Un autre type de mise en garde est, contrairement à l' decimal(m, d)endroit où la base de données empêchera les programmes d'insérer un nombre de plus de mchiffres, aucune validation de ce type n'existe avec double. Un programme peut insérer une valeur entrée par l'utilisateur de 20 chiffres et il finira par être enregistré en silence comme un montant inexact.


La première fois que j'ai vu une réponse comme celle-ci, intéressante. Q: Si j'écris un flottant comme 1.41 dans la base de données et pour une raison quelconque, je dois le multiplier par un nombre énorme dans mysql, comme 1.000.000.000.000. Le résultat arrondi sera-t-il exactement: 1.410.000.000.000?
roelleor

@roelleor Pour que le résultat soit exactement 1 410 1.410000000000000 000 000 (virgule comme séparateur de milliers), l'entrée est supposée être (douze décimales significatives), mais en la multipliant par 1 000 000 000 000 (soit 13 chiffres significatifs à gauche du séparateur décimal), nous travaillons avec au moins 25 chiffres combinés d'importance. Cela dépasse de loin les 15 disponibles pour un double, donc au niveau du design, je pense que ce serait très cassé.
antak

2

Au moment où cette question a été posée, personne ne pensait au prix du Bitcoin. Dans le cas du BTC, il est probablement insuffisant à utiliser DECIMAL(15,2). Si le Bitcoin monte à 100 000 $ ou plus, nous aurons besoin au moins DECIMAL(18,9)de prendre en charge les crypto-monnaies dans nos applications.

DECIMAL(18,9)prend 12 octets d'espace dans MySQL ( 4 octets pour 9 chiffres ).


> Un bitcoin peut être divisé en 8 décimales. Par conséquent, 0,00000001 BTC est le plus petit montant pouvant être traité dans une transaction. Je pense que vous voulez dire 8 au lieu de 9?
danger89

1
Je sais, mais 9 prend le même espace disque que 8. D'après les documents MySQL: "Les valeurs des colonnes DECIMAL sont stockées en utilisant un format binaire qui contient neuf chiffres décimaux dans 4 octets"
bizwiz

Désolée, maintenant je vous comprends. Merci.
danger89

2

Stocker de l'argent BIGINTmultiplié par 100 ou plus avec la raison d'utiliser moins d'espace de stockage n'a aucun sens dans toutes les situations "normales".

  • Pour rester aligné sur les PCGR, il suffit de stocker les devises dans DECIMAL(13,4)
  • Le manuel MySQL indique qu'il a besoin de 4 octets pour 9 chiffres pour être stocké DECIMAL.
  • DECIMAL(13,4) représente 9 chiffres + 4 chiffres de fraction (décimales) => 4 + 2 octets = 6 octets
  • comparer à 8 octets nécessaires pour stocker BIGINT.


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.