web-dev-qa-db-fra.com

Stocker de l'argent dans une colonne décimale - quelle précision et quelle ampleur?

J'utilise une colonne décimale pour stocker les valeurs monétaires dans une base de données, et aujourd'hui je me demandais quelle précision et quelle ampleur utiliser.

Étant donné que les colonnes censées avoir une largeur fixe sont plus efficaces, je pensais qu'il en allait de même pour les colonnes décimales. Est ce

Et quelle précision et quelle échelle devrais-je utiliser? Je pensais précision 24/8. Est-ce excessif, pas assez ou ok?


C'est ce que j'ai décidé de faire:

  • Stocker les taux de conversion (le cas échéant) dans la table de transaction elle-même, sous forme de float
  • Stocker la devise dans la table des comptes
  • Le montant de la transaction sera un DECIMAL(19,4)
  • Tous les calculs utilisant un taux de conversion seront traités par mon application afin que je garde le contrôle des problèmes d'arrondi.

Je ne pense pas qu'un flottant pour le taux de conversion soit un problème, puisqu'il s'agit surtout de référence, et je le placerai de toute façon en décimal.

Merci à tous pour votre précieuse contribution.

160
Ivan

Si vous recherchez une solution unique, je suggérerais que DECIMAL(19, 4) soit un choix populaire (un rapide Google confirme cela). Je pense que cela provient de l'ancien type de données VBA/Access/Jet Currency, le premier type décimal à virgule fixe de la langue; Decimal est uniquement venu dans le style "version 1.0" (c’est-à-dire n’a pas été complètement implémenté) dans VB6/VBA6/Jet 4.0.

La règle de base pour le stockage des valeurs décimales à virgule fixe est de stocker au moins une décimale de plus que nécessaire pour permettre l'arrondi. L’une des raisons de la mise en correspondance de l’ancien Currency dans le système frontal avec DECIMAL(19, 4) dans le système principal était que Currency affichait l’arrondi des banquiers par nature, alors que DECIMAL(p, s) arrondi par la troncature.

Une décimale supplémentaire dans la mémoire de DECIMAL permet de mettre en œuvre un algorithme d'arrondi personnalisé plutôt que de prendre la valeur par défaut du fournisseur (et l'arrondi des banquiers est pour le moins alarmant, pour un concepteur qui s'attend à ce que toutes les valeurs se terminant par .5 arrondir à zéro).

Oui, DECIMAL(24, 8) me parait être excessif. La plupart des devises sont citées à quatre ou cinq décimales. Je connais des situations où une échelle décimale de 8 (ou plus) est requise, mais il s'agit là d'un montant monétaire "normal" (par exemple, quatre décimales) a été calculé proportionnellement, ce qui implique que la précision décimale doit être réduite en conséquence (considérons également un type à virgule flottante dans de telles circonstances). Et personne n’a autant d’argent pour exiger une précision décimale de 24 :)

Cependant, plutôt que d’adopter une approche uniforme, certaines recherches pourraient être en ordre. Demandez à votre concepteur ou à votre expert de domaine les règles de comptabilité pouvant être applicables: GAAP, UE, etc. Je me souviens vaguement de certains transferts intra-États de l'UE avec des règles explicites pour arrondir à cinq décimales, donc en utilisant DECIMAL(p, 6) pour le stockage . Les comptables semblent généralement privilégier quatre décimales.


PS Évitez le type de données MONEY de SQL Server car il a de sérieux problèmes de précision lors de l’arrondi, entre autres considérations telles que la portabilité, etc. Voir blog d’Aaron Bertrand .


Microsoft et les concepteurs linguistiques ont choisi l'arrondi bancaire, car les concepteurs de matériel l'ont choisi [citation?]. Il est inscrit dans les normes de l'Institut des ingénieurs électriciens et électroniciens (IEEE), par exemple. Et les concepteurs de matériel l'ont choisi parce que les mathématiciens le préfèrent. Voir Wikipedia ; pour paraphraser: L'édition de 1906 de Probabilités et théorie des erreurs appelait cela la "règle de l'ordinateur" ("ordinateurs", signifiant des humains effectuant des calculs).

160
onedaywhen

Nous avons récemment mis en place un système qui doit gérer les valeurs dans plusieurs devises et les convertir entre elles. Nous avons compris certaines choses à la dure.

NE JAMAIS UTILISER DE NUMÉROS DE POINTS FLOTTANTS POUR DE L'ARGENT

L'arithmétique en virgule flottante introduit des imprécisions qui peuvent ne pas être remarquées jusqu'à ce qu'elles aient foiré quelque chose. Toutes les valeurs doivent être stockées sous forme de nombres entiers ou décimales fixes. Si vous choisissez d’utiliser un type décimal fixe, assurez-vous de bien comprendre ce que ce type fait sous le capot (c’est-à-dire qu’il utilise en interne un nombre entier ou flottant. type).

Lorsque vous devez effectuer des calculs ou des conversions:

  1. Convertir des valeurs en virgule flottante
  2. Calculer la nouvelle valeur
  3. Arrondis le nombre et convertis-le en un entier

Lors de la conversion d'un nombre à virgule flottante en un entier à l'étape 3, ne le convertissez pas simplement - utilisez une fonction mathématique pour le arrondir en premier. Ce sera généralement round, bien que dans des cas particuliers cela puisse être floor ou ceil. Connaissez la différence et choisissez avec soin.

Stocke le type d'un nombre à côté de la valeur

Cela peut ne pas être aussi important pour vous si vous ne gérez qu'une seule devise, mais c'était important pour nous lorsque nous traitons plusieurs devises. Nous avons utilisé le code à 3 caractères pour une devise, telle que USD, GBP, JPY, EUR, etc.

Selon la situation, il peut également être utile de stocker:

  • Si le nombre est avant ou après impôt (et quel était le taux d'imposition)
  • Si le nombre est le résultat d'une conversion (et de quoi il a été converti)

Connaître les limites de précision des nombres que vous traitez

Pour les valeurs réelles, vous voulez être aussi précis que la plus petite unité de la devise. Cela signifie que vous n'avez pas de valeurs inférieures à un cent, un centime, un yen, un fen, etc. Ne stockez pas les valeurs avec une précision supérieure à celle-là sans raison.

En interne, vous pouvez choisir de traiter des valeurs plus petites, auquel cas il s’agit d’un type différent de la valeur monétaire . Assurez-vous que votre code sait lequel est lequel et ne les mélange pas. Évitez d’utiliser des valeurs en virgule flottante même ici.


En additionnant toutes ces règles, nous avons choisi les règles suivantes. Dans le code courant, les devises sont stockées en utilisant un entier pour la plus petite unité.

class Currency {
   String code;       //  eg "USD"
   int value;         //  eg 2500
   boolean converted;
}

class Price {
   Currency grossValue;
   Currency netValue;
   Tax taxRate;
}

Dans la base de données, les valeurs sont stockées sous forme de chaîne au format suivant:

USD:2500

Cela stocke la valeur de 25,00 $. Nous n'avons pu le faire que parce que le code traitant des devises ne doit pas nécessairement se trouver dans la couche de base de données, de sorte que toutes les valeurs peuvent d'abord être converties en mémoire. D'autres situations se prêteront sans doute à d'autres solutions.


Et au cas où je ne l'aurais pas dit plus tôt, n'utilisez pas float!

93
Marcus Downing

Lorsque vous manipulez de l’argent dans MySQL, utilisez DECIMAL (13,2) si vous connaissez la précision de vos valeurs monétaires ou utilisez DOUBLE si vous souhaitez simplement obtenir une valeur approximative rapide et satisfaisante. Ainsi, si votre application doit gérer des valeurs monétaires allant jusqu'à un billion de dollars (ou en euros ou en livres sterling), cela devrait fonctionner:

DECIMAL(13, 2)

Ou, si vous devez vous conformer à GAAP , utilisez:

DECIMAL(13, 4)
3
pollux1er

Quatre décimales vous donneraient la précision nécessaire pour stocker les plus petites sous-unités monétaires du monde. Vous pouvez le réduire davantage si vous avez besoin d'exactitude en matière de micropaiement (nanopaiement?!).

Moi aussi, je préfère DECIMAL aux types d'argent spécifiques aux SGBD, vous êtes plus en sécurité en conservant ce type de logique dans l'application OMI. Une autre approche dans le même sens consiste simplement à utiliser un entier [long], avec un formatage en ¤unit.subunit pour la lisibilité humaine (¤ = symbole monétaire) effectué au niveau de l'application.

2
bobince

Si vous envisagez d'effectuer des opérations arithmétiques dans la base de données (en multipliant les taux de facturation, etc.), vous souhaiterez probablement beaucoup plus de précision que ne le suggèrent les gens ici, pour les mêmes raisons que vous n'auriez jamais. vouloir utiliser autre chose qu'une valeur à virgule flottante double précision dans le code de l'application.

1
Hank Gay

Vous devrez parfois atteindre moins d’un centime et certaines monnaies internationales utilisent de très grandes démoniations. Par exemple, vous pourriez facturer à vos clients 0,088 centimes par transaction. Dans ma base de données Oracle, les colonnes sont définies comme NUMBER (20,4)

1
WW.

Le type de données money sur SQL Server comporte quatre chiffres après la virgule.

De la documentation en ligne de SQL Server 2000:

Les données monétaires représentent des montants d'argent positifs ou négatifs. Dans Microsoft® SQL Server ™ 2000, les données monétaires sont stockées à l'aide des types de données money et smallmoney. Les données monétaires peuvent être stockées avec une précision de quatre décimales. Utilisez le type de données money pour stocker des valeurs comprises entre -922.337.203.685.477.5808 et +922.337.203.685.477.5807 (nécessite 8 octets pour stocker une valeur). Utilisez le type de données smallmoney pour stocker des valeurs comprises entre -214748,3648 et 214,748,3647 (4 octets sont nécessaires pour stocker une valeur). Si un plus grand nombre de décimales est requis, utilisez plutôt le type de données décimal.

1
Austin Salonen

Une réponse tardive ici, mais j'ai utilisé

DECIMAL(13,2)

ce qui, j’ai raison, devrait permettre jusqu’à 99 999 999 999,99.

0
Mike Upjohn

Si vous utilisiez IBM Informix Dynamic Server, vous auriez un type MONEY qui est une variante mineure du type DECIMAL ou NUMERIC. C'est toujours un type à virgule fixe (alors que DECIMAL peut être un type à virgule flottante). Vous pouvez spécifier une échelle de 1 à 32 et une précision de 0 à 32 (par défaut, une échelle de 16 et une précision de 2). Ainsi, en fonction de ce que vous devez stocker, vous pouvez utiliser DECIMAL (16,2) - suffisamment grand pour contenir le déficit fédéral américain, au cent près - ou vous pouvez utiliser une plage plus petite ou des décimales plus importantes.

0
Jonathan Leffler

Je penserais que, dans une large mesure, vos exigences ou celles de vos clients devraient dicter quelle précision et quelle ampleur utiliser. Par exemple, pour le site Web de commerce électronique sur lequel je travaille et traite uniquement de l'argent en GBP, il m'a été demandé de le conserver en décimal (6, 2).

0
ayaz