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

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

puisque prétendument les colonnes de char d'une largeur fixe sont plus efficaces, je pensais que la même chose pourrait être vraie pour les colonnes décimales. S'agit-il?

Et quelle précision et l'échelle dois-je utiliser? Je pensais précision 24/8. C'est que overkill, ou pas assez 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, comme un flottant
  • stocker la monnaie dans la table de Compte
  • le montant de la transaction sera un DECIMAL(19,4)
  • tous les calculs utilisant un taux de conversion seront traités par mon application de sorte que je garde le contrôle des questions d'arrondissement

Je ne pense pas que flottant pour le taux de conversion est un problème, car il est principalement pour référence, et je vais le mouler à une décimale de toute façon.

merci à tous pour votre précieuse contribution.

146
demandé sur Nick Chammas 2008-10-22 08:08:18

10 réponses

si vous recherchez une taille unique, je dirais que DECIMAL(19, 4) est un choix populaire (un Google rapide le confirme). Je pense que cela provient de l'ancien type de données VBA/Access/Jet Currency, qui est le premier type décimal à point fixe dans la langue; Decimal est seulement venu dans le style "version 1.0" (c.-à-d. pas entièrement mis en œuvre) dans VB6/VBA6/Jet 4.0.

la règle empirique pour stockage de valeurs décimales à point fixe est de stocker à moins une décimale après la virgule que vous avez réellement besoin pour permettre l'arrondissement. L'une des raisons pour lesquelles on a établi une correspondance entre l'ancien type Currency à l'avant et le type DECIMAL(19, 4) à l'arrière était que Currency montrait que les banquiers arrondissaient leurs chiffres par nature, alors que DECIMAL(p, s) était arrondi par troncature.

une place décimale supplémentaire dans le stockage pour DECIMAL permet un algorithme d'arrondissement personnalisé pour être mis en œuvre plutôt que de prendre le défaut du vendeur (et l'arrondissement des banquiers est alarmant, pour le moins, pour un designer qui s'attend à ce que toutes les valeurs se terminent .5 arrondir à partir de zéro).

Oui, DECIMAL(24, 8) il semble exagéré pour moi. La plupart des devises sont cotées à quatre ou cinq décimales. Je connais des situations où une échelle décimale de 8 (ou plus) est nécessaire, mais c'est là où un montant monétaire "normal" (disons quatre décimales) a été au prorata, ce qui implique que la précision décimale devrait être réduite en conséquence (également dans de telles circonstances, il peut s'agir d'un point flottant. Et personne n'a autant d'argent aujourd'hui pour exiger une précision décimale de 24:)

toutefois, au lieu d'une approche uniformisée, certaines recherches pourraient s'imposer. Renseignez-vous auprès de votre concepteur ou de votre expert de domaine sur les règles comptables qui peuvent s'appliquer: GAAP, UE, etc. Je me souviens vaguement de certains transferts intra-états de l'UE avec des règles explicites d'arrondissement à la cinquième décimale, donc en utilisant DECIMAL(p, 6) pour le stockage. Comptables généralement semblent favorables à quatre décimales.


PS éviter le type de données MONEY de SQL Server parce qu'il a de graves problèmes avec précision lors de l'arrondissement, entre autres considérations telles que la portabilité, etc Voir le blog D'Aaron Bertrand .


de Microsoft et de la langue concepteurs ont choisi l'arrondi parce que les concepteurs de matériel choisi [citation?]. Il est les normes de L'Institute of Electrical and Electronics Engineers (IEEE), par exemple. Et les concepteurs de matériel choisi parce que les mathématiciens préfèrent. Voir Wikipedia ; pour paraphraser: l'édition de 1906 de Probability and Theory of Errors a appelé cette 'règle de l'ordinateur' ("ordinateurs" signifie les humains qui effectuent des calculs).

145
répondu onedaywhen 2018-05-09 09:39:56

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

NEVER USE FLOATING POINT NUMBERS FOR MONEY

l'arithmétique à virgule flottante introduit des inexactitudes qui peuvent ne pas être remarquées jusqu'à ce qu'ils aient foiré quelque chose. Toutes les valeurs doivent être stockés comme des entiers ou des décimaux types, et si vous choisissez d'utiliser un fixed-decimal type puis assurez-vous de comprendre exactement ce que ce type fait sous le capot (c'est-à-dire, est-ce qu'il utilise en interne un type entier ou à virgule flottante).

lorsque vous devez effectuer des calculs ou des conversions:

  1. Convertir des valeurs à virgule flottante
  2. calculer la nouvelle valeur
  3. arrondir le nombre et le convertir en un entier

lors de la conversion d'un nombre de virgule flottante de nouveau à un entier à l'étape 3, ne le jetez pas simplement - utilisez une fonction mathématique pour arrondir d'abord. Ce sera généralement round , bien que dans des cas spéciaux, il pourrait être floor ou ceil . Connaître la différence et choisir avec soin.

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

ce n'est peut-être pas aussi important pour vous si vous ne manipulez qu'une seule monnaie, mais c'était important pour nous dans gérer plusieurs devises. Nous avons utilisé le code à 3 caractères pour une devise, comme USD, GBP, JPY, EUR, etc.

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

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

connaître les limites de précision des nombres que vous avez affaire avec

pour les valeurs réelles, vous voulez être aussi précis que la plus petite unité de la monnaie. Cela signifie que vous n'avez pas de valeurs plus petites qu'un cent, un penny, un yen, un fen, etc. N'enregistrez pas les valeurs avec une plus grande précision que cela sans raison.

à l'interne, vous pouvez choisir de traiter avec des valeurs plus petites, dans ce cas, c'est un type différent de valeur de devise . Assurez-vous que votre code sait qui est qui et ne pas les mélanger. Évitez d'utiliser des valeurs flottantes, 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 dans le format suivant:

USD:2500

qui conserve la valeur de $25.00. Nous avons été en mesure pour faire cela seulement parce que le code qui traite avec les devises n'a pas besoin d'être dans la couche de base de données elle-même, de sorte que toutes les valeurs peuvent être converties en mémoire en premier. D'autres situations se prêteront sans doute à d'autres solutions.


et au cas où je ne l'ai pas dit clairement plus tôt, n'utilisez pas de flotteur!

86
répondu Marcus Downing 2008-10-22 12:47:39

lorsque vous manipulez de l'argent dans MySQL, utilisez la décimale(13,2) si vous connaissez la précision de vos valeurs en argent ou utilisez le DOUBLE si vous voulez juste un bon rapide-assez de valeur approximative. Donc, si votre application a besoin de gérer des valeurs d'argent jusqu'à un billion de dollars( ou euros ou livres), alors cela devrait fonctionner:

DECIMAL(13, 2)

ou, si vous devez vous conformer à GAAP alors utiliser:

DECIMAL(13, 4)
3
répondu pollux1er 2017-10-20 14:15:28

4 décimales vous donneraient la précision pour stocker les plus petites sous-unités de devise du monde. Vous pouvez l'enlever plus bas si vous avez besoin de micropaiement (nanopaiement?!) exactitude.

moi aussi, je préfère DECIMAL à SGBD spécifique de l'argent, vous êtes sûr de garder ce genre de logique dans l'application de l'OMI. Une autre approche similaire consiste simplement à utiliser un [long] entier, avec le formatage en ¤unité.sous-unité pour la lisibilité humaine (¤=symbole de devise) le niveau d'application.

2
répondu bobince 2016-08-02 00:09:13

le type de données argent sur le serveur SQL a quatre chiffres après la décimale.

de SQL Server 2000 livres en ligne:

les données monétaires représentent des montants positifs ou négatifs de monnaie. Dans Microsoft ® SQL Server™ 2000, les données monétaires sont stockées en utilisant les 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 dans l'intervalle de -922.337.203.685.477.5808 à +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 dans l'intervalle de -214,748.3648 à 214 748.3647 (nécessite 4 octets pour stocker une valeur). Si un plus grand nombre de décimales sont nécessaires, utilisez le type de données décimal au lieu.

1
répondu Austin Salonen 2008-10-22 04:10:49

parfois, vous aurez besoin d'aller à moins d'un cent et il ya des devises internationales qui utilisent de très grandes démoniations. Par exemple, vous pourriez facturer à vos clients 0,088 cent par transaction. Dans ma base de données Oracle les colonnes sont définies comme nombre (20,4)

1
répondu WW. 2008-10-22 06:11:10

si vous allez faire n'importe quelle sorte d'opérations arithmétiques dans le DB (en multipliant les taux de facturation et ainsi de suite), vous voudrez probablement beaucoup plus de précision que les gens ici suggèrent, pour les mêmes raisons que vous ne voudriez jamais utiliser quoi que ce soit de moins qu'une double précision virgule flottante dans le code d'application.

1
répondu Hank Gay 2008-10-22 11:34:07

si vous utilisiez IBM Informix Dynamic Server, vous auriez un type de monnaie qui est une variante mineure sur le type décimal ou numérique. Il s'agit toujours d'un type à point fixe (alors que décimal peut être un type à virgule flottante). Vous pouvez spécifier une échelle de 1 à 32, et une précision de 0 à 32 (défaut à une échelle de 16 et une précision de 2). Donc, selon ce que vous avez besoin de stocker, vous pourriez utiliser décimal (16,2) - encore assez grand pour contenir le déficit fédéral américain, au cent le plus proche - ou vous peut utiliser une plus petite portée, ou plus de décimales.

0
répondu Jonathan Leffler 2008-10-22 06:05:43

je pense que pour une grande partie vos exigences ou celles de votre client devraient dicter quelle précision et quelle échelle utiliser. Par exemple, pour le site de commerce électronique sur lequel je travaille qui traite de L'argent en GBP seulement, j'ai été obligé de le garder à la décimale( 6, 2 ).

0
répondu ayaz 2008-10-22 06:16:16

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

DECIMAL(13,2)

ce qui, je pense, devrait permettre jusqu'à 99 999 999.699.

0
répondu Mike Upjohn 2015-08-24 12:54:16