Devriez-vous choisir les types de données MONEY ou DECIMAL (x, y) dans SQL Server?

443

Je suis curieux de savoir s'il existe ou non une réelle différence entre le moneytype de données et quelque chose comme decimal(19,4)(c'est ce que l'argent utilise en interne, je crois).

Je suis conscient que moneyc'est spécifique à SQL Server. Je veux savoir s'il y a une raison impérieuse de choisir l'un plutôt que l'autre; la plupart des exemples SQL Server (par exemple la base de données AdventureWorks) utilisent moneyet non decimalpour des choses comme les informations de prix.

Dois-je simplement continuer à utiliser le type de données money, ou y a-t-il un avantage à utiliser la décimale à la place? L'argent est moins de caractères à taper, mais ce n'est pas une raison valable :)

Wayne Molina
la source
12
DECIMAL(19, 4) est un choix populaire vérifier ce aussi vérifier ici du monde Monnaie Formats de décider combien de décimales à l' utilisation, l' espoir aide.
shaijut
Je me suis demandé pourquoi le type de données money a 4 décimales .. et non 2. c'est-à-dire 100 cents dans un dollar donc seulement 2 décimales sont nécessaires? Pour stocker un dossier d'argent de moins de 9999,99 $, j'allais utiliser un type de données décimal (6,2). Je ne me soucie pas de diviser ou de multiplier les calculs, juste de stocker et de sommer ..
Allan F

Réponses:

326

Vous ne devez jamais utiliser d'argent. Ce n'est pas précis et ce sont des ordures pures; utilisez toujours décimal / numérique.

Exécutez ceci pour voir ce que je veux dire:

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

Sortie: 2949.0000 2949.8525

À certaines des personnes qui ont dit que vous ne divisez pas l'argent par l'argent:

Voici l'une de mes requêtes pour calculer les corrélations, et changer cela en argent donne de mauvais résultats.

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
SQLMenace
la source
62
"Jamais" est un mot fort. "L'argent" est utile pour diffuser des résultats sur ce type pour les afficher à l'utilisateur d'une manière sensible à la culture, mais vous avez raison, c'est très mauvais à utiliser pour les calculs lui-même.
Joel Coehoorn
37
Votre exemple n'a pas de sens, car personne ne multipliera jamais deux objets de type argent. Si vous voulez prouver votre point, vous devez comparer la multiplication d'une monnaie par une décimale à la multiplication d'une décimale par une décimale.
Brian
27
.. mais on se demande toujours pourquoi l'argent * l'argent n'aurait pas la précision de l'argent.
Apprendre le
4
@Learning: il a une précision d'argent. Cependant, vous vous retrouvez toujours avec des erreurs d'arrondi qui peuvent s'accumuler au fil du temps. Le type décimal n'utilise pas d'arithmétique binaire: il garantit qu'il obtient les mêmes résultats de base 10 que vous le feriez en le faisant sur papier.
Joel Coehoorn
56
Multiplication et division de moneyplus de moneycôté, cette «illustration» est manipulatrice. C'est un fait documenté qui moneya une précision fixe et très limitée. Dans de tels cas, il faut d'abord multiplier, puis diviser. Modifiez l'ordre des opérateurs dans cet exemple et vous obtiendrez des résultats identiques. A moneyest essentiellement un entier 64 bits, et si vous deviez gérer des nombres entiers, vous vous multiplieriez avant de diviser.
Andriy M
273

SQLMenace a déclaré que l'argent était inexact. Mais vous ne multipliez / divisez pas l'argent par l'argent! Combien coûte 3 dollars multiplié par 50 cents? 150 dollarcents? Vous multipliez / divisez l'argent par des scalaires, qui doivent être décimaux.

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

Résultats dans le bon résultat:

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

moneyest bon tant que vous n'avez pas besoin de plus de 4 chiffres décimaux et que vous vous assurez que vos scalaires - qui ne représentent pas de l'argent - sont decimals.

configurateur
la source
57
combien de pièces de 1 cent un billet d'un dollar peut-il vous procurer? une réponse à cela nécessite de l'argent / de l'argent.
Apprendre le
48
@Learning dans ce cas, le résultat n'est pas de l'argent, mais un flottant. (Analyse dimensionnelle de base.)
Richard
11
@Learning: demandez-vous à la base de données combien de cents dans un dollar beaucoup? Quoi qu'il en soit, cela retournerait le bon résultat. Son problème était que l'argent / l'argent n'était précis qu'à quatre chiffres (il était de 0,2949), puis multiplié par 10000, il devenait 2949,0000.
configurateur le
26
@mson Il a raison et ne fait pas de critiques personnelles comme vous l'avez fait sur la base d'une remarque d'une ligne, ce n'est pas utile. S'il ne divise pas par 0,01 $ mais par 0,01, alors le résultat est de 100 $ au lieu de 100. Il y a 100 cents dans un dollar, pas 100 $. Les unités sont importantes! Il y a certainement un grand endroit pour plonger, et peut-être pour se multiplier, argent par argent.
andrewb
19
Si je veux dépenser 1 000 $ pour acheter des actions au prix de 36 $, n'est-ce pas une utilisation légitime de money / money? La réponse est des unités entières sans signe dollar attaché, ce qui est correct! C'est un scénario parfaitement raisonnable, suggérant qu'en raison de cas de bord étranges comme celui-ci, ce moneyn'est pas un bon type de données à utiliser, car le résultat est toujours tronqué pour s'adapter moneyau lieu de suivre les règles normales de précision et d'échelle. Que faire si vous souhaitez calculer l'écart type d'un ensemble de moneyvaleurs? Oui, Sqrt(Sum(money * money))(simplifié) a du sens.
ErikE
59

Tout est dangereux si vous ne savez pas ce que vous faites

Même les types décimaux de haute précision ne peuvent pas sauver la situation:

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

1,000000 <- Devrait être 0,6000000


Les moneytypes sont des entiers

Les représentations textuelles de smallmoneyet decimal(10,4)peuvent se ressembler, mais cela ne les rend pas interchangeables. Vous grincer des dents quand vous voyez les dates stockées sous varchar(10)? C'est la même chose.

Dans les coulisses, money/ ne smallmoneysont qu'un bigint/ int La virgule décimale dans la représentation textuelle moneyest un fluff visuel, tout comme les tirets d'une date aaaa-mm-jj. SQL ne les stocke pas réellement en interne.

En ce qui concerne decimalvs money, choisissez ce qui convient à vos besoins. Les moneytypes existent car le stockage des valeurs comptables sous forme de multiples entiers de 1/10000ème d'unité est très courant. De plus, si vous traitez de l'argent réel et des calculs au-delà de la simple addition et soustraction, vous ne devriez pas le faire au niveau de la base de données! Faites-le au niveau de l'application avec une bibliothèque qui prend en charge l'arrondi bancaire (IEEE 754)

Anon
la source
1
Pouvez-vous expliquer ce qui s'est passé dans cet exemple?
Sergey Popov
4
Débordement d'échelle. Aux petites échelles, numérique (a, b) * numérique (c, d) donne numérique (a-b + c-d + 1, max (b, d)). Cependant, si (a + b + c + d)> 38, SQL limite l'échelle, privant la précision du côté fraction pour remplir le côté entier, provoquant l'erreur d'arrondi.
Anon
Tous les calculs numériques sont susceptibles de perdre de la précision en raison de la mise à l'échelle: à la place, sélectionnez 1000000 * @ num1 * @ num2
Mitch Wheat
L'exemple d'Anon est spécifique à la version et à la base de données. mais le point attention est valable. dans sqlanywhere version 1.1, l'exemple donne correctement 0.600000. (Je sais que nous parlons ici de ms sql). un autre point sur le type d'argent manquant dans une autre base de données, il existe des moyens appelant décimal ou numérique comme argent, comme la création de domaine.
gg89
3
Je pense que c'est la réponse la plus éclairante parce que vous avez expliqué non seulement les erreurs qui se propagent, mais ce qui se passe vraiment derrière la scène et pourquoi l'ARGENT existe en premier lieu. Je ne sais pas pourquoi il a fallu 4 ans pour obtenir cette réponse, mais c'est peut-être parce qu'il y a trop d'attention sur le "problème" de calcul, et pas tellement sur le pourquoi et le comment de l'argent par rapport à la décimale.
Steve Sether
44

Je me rends compte que WayneM a déclaré qu'il savait que l'argent est spécifique à SQL Server. Cependant, il demande s'il y a des raisons d'utiliser de l'argent au-dessus de la décimale ou vice versa et je pense qu'une raison évidente doit encore être indiquée et que l'utilisation de la décimale signifie que c'est une chose de moins à s'inquiéter si vous devez changer votre SGBD - ce qui peut arriver.

Rendez vos systèmes aussi flexibles que possible!

doyen
la source
1
Peut-être, mais en théorie, vous pourriez déclarer un domaine nommé Money dans un autre SGBD (qui prend en charge la déclaration de domaines).
débatteur le
En tant que personne qui convertit actuellement une base de données SQL Server en Amazon Redshift, je peux garantir qu'il s'agit d'un véritable problème. Essayez d'éviter les types de données sur mesure pour une plate-forme de base de données particulière, sauf s'il existe de très bonnes raisons commerciales de les utiliser.
Nathan Griffiths
@Nathn étant donné le système de type faible de Redshift par rapport à PostgreSQL ou SQL Server, par exemple aucun datetype, je dirais que vous aurez toujours de tels problèmes. Vous devez dire "N'utilisez pas de types obsolètes lorsque la base de données fournit déjà de meilleurs types, plus conformes aux normes et met en garde contre ceux qui sont obsolètes".
Panagiotis Kanavos
@PanagiotisKanavos - l'argent n'est pas déprécié
Martin Smith
@MartinSmith a été choqué de voir cela, car il ne peut pas réellement gérer des valeurs monétaires comme BTC en 2017. Ou faire la différence entre les montants GBP et EUR - même s'ils évoluent vers la parité: P. Quoi qu'il en soit, le passage à Redshift introduit beaucoup de douleur
Panagiotis Kanavos
32

Eh bien, j'aime bien MONEY! C'est un octet moins cher que DECIMAL, et les calculs sont plus rapides car (sous les couvertures) les opérations d'addition et de soustraction sont essentiellement des opérations entières. L'exemple de @ SQLMenace - qui est un grand avertissement pour les ignorants - pourrait également être appliqué aux INTegers, où le résultat serait nul. Mais ce n'est pas une raison pour ne pas utiliser d'entiers - le cas échéant .

Il est donc parfaitement «sûr» et approprié de l'utiliser MONEYlorsque vous traitez MONEYet de l'utiliser selon les règles mathématiques qu'il suit (comme INTeger).

Aurait-il été préférable que SQL Server promeuve la division et la multiplication des MONEYs en DECIMALs (ou FLOATs?) - peut-être, mais ils n'ont pas choisi de le faire; ils n'ont pas non plus choisi de promouvoir les INTegers en FLOATs lors de leur division.

MONEYn'a pas de problème de précision; cela permet DECIMALd'avoir un type intermédiaire plus grand utilisé pendant les calculs n'est qu'une «fonctionnalité» de l'utilisation de ce type (et je ne suis pas vraiment sûr de l'étendue de cette «fonctionnalité»).

Pour répondre à la question spécifique, une "raison impérieuse"? Eh bien, si vous voulez des performances maximales absolues dans un SUM(x)xpourrait être l'un DECIMALou l' autre MONEY, alors vous MONEYaurez un avantage.

N'oubliez pas non plus qu'il s'agit d'un cousin plus petit - SMALLMONEYjuste 4 octets, mais il atteint son maximum 214,748.3647- ce qui est assez petit pour de l'argent - et n'est donc pas souvent un bon choix.

Pour prouver l'intérêt d'utiliser des types intermédiaires plus grands, si vous affectez explicitement l'intermédiaire à une variable, DECIMALle même problème se produit:

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

Produit 2950.0000(d'accord, donc au moins DECIMALarrondi plutôt que MONEYtronqué, comme un entier.)

dsz
la source
21
MONEYest un octet de moins qu'un grand DECIMAL , avec jusqu'à 19 chiffres de précision. Cependant, la plupart des calculs monétaires réels (jusqu'à 9,99 M $) peuvent tenir dans un DECIMAL(9, 2), qui ne nécessite que cinq octets. Vous pouvez économiser de la taille, vous soucier moins des erreurs d'arrondi et rendre votre code plus portable.
Bien que @JonofAllTrades soit correct, vous pouvez également obtenir des performances entières en utilisant simplement un entier contenant des sous ou des cents, et enregistrer l'octet supplémentaire qui code la position du point décimal, et qui doit être vérifié lors de l'ajout de décimales ensemble.
dsz
"Donc, il est parfaitement" sûr "et approprié d'utiliser de l'ARGENT lorsque vous traitez avec de l'ARGENT et de l'utiliser selon les règles mathématiques qu'il suit" -> cependant, voir aussi la réponse d'Anon: "Tout est dangereux si vous ne le faites pas Sais ce que tu fais". Vous ne pouvez jamais prédire comment les gens finiront par interroger le système que vous créez, mieux pour éviter la possibilité d'une mauvaise utilisation lorsque vous le pouvez. Le minuscule gain de stockage n'en vaut pas la peine à mon humble avis.
Nathan Griffiths
1
Essayez de stocker une valeur Bitcoin. Il a 8 décimales
Panagiotis Kanavos
14

Nous venons de rencontrer un problème très similaire et je suis maintenant très bien un +1 pour ne jamais utiliser Money sauf dans la présentation de haut niveau. Nous avons plusieurs tableaux (en fait un bon de vente et une facture de vente), chacun contenant un ou plusieurs champs Money pour des raisons historiques, et nous devons effectuer un calcul au prorata pour déterminer la proportion de la facture totale que la taxe est pertinente pour chacun. ligne sur le bon de vente. Notre calcul est

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

Il en résulte un calcul réel argent / argent qui provoque des erreurs d'échelle sur la partie de division, qui se multiplient ensuite dans une proportion de TVA incorrecte. Lorsque ces valeurs sont ajoutées par la suite, nous nous retrouvons avec une somme des proportions de TVA qui ne correspondent pas à la valeur totale de la facture. Si l'une des valeurs entre parenthèses avait été décimale (je suis sur le point de transposer l'une d'entre elles en tant que telle), la proportion de TVA serait correcte.

Lorsque les crochets n'étaient pas là à l'origine, cela fonctionnait, je suppose qu'en raison des valeurs plus importantes impliquées, cela simulait effectivement une échelle plus élevée. Nous avons ajouté les crochets parce qu'il effectuait d'abord la multiplication, ce qui dans certains cas rares soufflait la précision disponible pour le calcul, mais cela a maintenant causé cette erreur beaucoup plus courante.

Kaideejee
la source
8
Mais il ne le fait que parce qu'un développeur ignorant a ignoré les règles de calcul de la TVA et les limites de précision documentées de l'argent.
TomTom
1
@TomTom, mais l'argument que vous faites à propos de la possibilité d'une mauvaise utilisation de ce type de données est un argument en faveur de ne pas l'utiliser du tout.
Nathan Griffiths
@Nathan Non. Je souligne que l'argument donné comme raison de ne jamais l'utiliser est fondamentalement un développeur incompétent, donc l'argument est faux.
TomTom
1
@TomTom, malheureusement, il existe de nombreux développeurs incompétents (ainsi que de nombreux géniaux) et pour moi, à moins que je ne puisse garantir comment ces données allaient être interrogées à l'avenir et que personne n'allait jamais commettre le genre d'erreurs décrites ici , mieux vaut pécher par excès de prudence et utiliser un type décimal. Cela dit, après avoir lu toutes ces réponses, je peux voir qu'il existe des cas d'utilisation spécifiques où l'argent serait un type optimal à utiliser, je ne l'utiliserais pas à moins qu'il n'y ait un très bon cas d'utilisation (par exemple, la colonne ne sera jamais être agrégés par SUM, en vrac chargeant de grandes quantités de données financières
Nathan Griffiths
@TomTom ce n'est pas seulement les limitations de précision. La représentation interne peut également provoquer des problèmes. L'argent est un type pratique pour attraper les développeurs ignorants, pas un excellent type que les développeurs utilisent à mauvais escient. L'exemple de TVA, quelles que soient les règles de calcul, devrait clairement effrayer les développeurs non ignorants lorsqu'ils appliquent le spécifique au général.
Gerard ONeill
12

En contrepoint de l'orientation générale des autres réponses. Voir les nombreux avantages de l'argent… Type de données! dans le Guide du moteur relationnel de SQLCAT

Plus précisément, je voudrais souligner ce qui suit

En travaillant sur les implémentations des clients, nous avons trouvé des chiffres de performance intéressants concernant le type de données money. Par exemple, lorsque Analysis Services a été défini sur le type de données monétaire (de double) pour correspondre au type de données monétaire SQL Server, la vitesse de traitement (lignes / s) a été améliorée de 13%. Pour obtenir des performances plus rapides dans SQL Server Integration Services (SSIS) pour charger 1,18 To en moins de trente minutes, comme indiqué dans SSIS 2008 - Record record world performance ETL, il a été observé que la modification des quatre colonnes décimales (9,2) avec une taille de 5 octets dans la table TPC-H LINEITEM en argent (8 octets) ont amélioré la vitesse d'insertion en bloc de 20% ... La raison de l'amélioration des performances est due au protocole TDS (Tabular Data Stream) de SQL Server, qui a le principe de conception clé pour transférer des données sous forme binaire compacte et aussi proche que possible du format de stockage interne de SQL Server. Empiriquement, cela a été observé lors du SSIS 2008 - test de performance record mondial ETL utilisant Kernrate; le protocole a chuté de manière significative lorsque le type de données a été changé en argent à partir de décimal. Cela rend le transfert de données aussi efficace que possible. Un type de données complexe nécessite des cycles d'analyse et d'UC supplémentaires pour gérer qu'un type à largeur fixe.

La réponse à la question est donc "ça dépend". Vous devez être plus prudent avec certaines opérations arithmétiques pour préserver la précision, mais vous constaterez peut-être que des considérations de performances en valent la peine.

Martin Smith
la source
Comment stockeriez-vous alors le bitcoin ?
Panagiotis Kanavos
@PanagiotisKanavos - Je n'en ai aucune idée. Je n'ai jamais étudié le bitcoin et je n'y connais pratiquement rien!
Martin Smith
6

Je veux donner une vision différente de MONEY par rapport à NUMERICAL, en grande partie basée sur ma propre expertise et mon expérience ... Mon point de vue ici est MONEY, parce que je travaille avec lui depuis longtemps et que je n'ai jamais beaucoup utilisé NUMERICAL. .

MONEY Pro:

  • Type de données natif . Il utilise un type de données natif ( entier ) identique à un registre CPU (32 ou 64 bits), donc le calcul n'a pas besoin de surcharge inutile donc il est plus petit et plus rapide ... L'ARGENT a besoin de 8 octets et NUMÉRIQUE (19, 4 ) a besoin de 9 octets (12,5% plus gros) ...

    L'ARGENT est plus rapide tant qu'il est utilisé car il devait l'être (en argent). À quelle vitesse? Mon simple SUMtest sur 1 million de données montre que MONEY est de 275 ms et NUMERIC de 517 ms ... C'est presque deux fois plus rapide ... Pourquoi le test SUM? Voir le prochain point Pro

  • Meilleur pour l'argent . L'ARGENT est idéal pour stocker de l'argent et effectuer des opérations, par exemple, en comptabilité. Un seul rapport peut exécuter des millions d'ajouts (SUM) et quelques multiplications une fois l'opération SUM terminée. Pour les très grandes applications comptables, il est presque deux fois plus rapide , et il est extrêmement important ...
  • Faible précision de l'argent . L'argent dans la vraie vie n'a pas besoin d'être très précis. Je veux dire, beaucoup de gens peuvent se soucier d'environ 1 cent USD, mais qu'en est-il de 0,01 cent USD? En fait, dans mon pays, les banques ne se soucient plus des cents (chiffre après virgule décimale); Je ne connais pas la banque américaine ou un autre pays ...

ARGENT Con:

  • Précision limitée . L'ARGENT n'a qu'une précision de quatre chiffres (après la virgule), il doit donc être converti avant d'effectuer des opérations telles que la division ... Mais là encore, il moneyn'a pas besoin d'être aussi précis et est destiné à être utilisé comme de l'argent, pas seulement un nombre...

Mais ... Gros, mais voici même votre application impliquée en argent réel, mais ne l'utilisez pas dans de nombreuses opérations SUM, comme en comptabilité. Si vous utilisez à la place de nombreuses divisions et multiplications, vous ne devez pas utiliser ARGENT ...

Susilo
la source
1
Si vous voulez dire que l'argent est plus rapide que la décimale, vous devez nous dire des choses comme quels rdbms, sur quel matériel, quel système d'exploitation, avec quelles données spécifiques exécutant quelle requête spécifique dont vous parlez. De plus, s'il n'est pas COMPLETEMENT exact, je ne fais aucune opération financière avec lui, car le fisc sera plutôt mécontent de récupérer de mauvais chiffres. Vous vous souciez du millième centime si vous traitez avec la devise américaine par exemple. Si l'argent ne fait pas cela, ce n'est pas utilisable.
Haakon Løtveit
3
@ HaakonLøtveit, l'ensemble de ce fil de questions-réponses porte sur le type de données SQL Server "money", donc je ne pense pas qu'ils aient besoin de le préciser dans la réponse. L'argent peut être plus rapide à utiliser que la décimale dans certaines circonstances (par exemple, le chargement de données), voir la réponse de Martin Smith pour plus de détails. Je suis d'accord avec la majorité de cette réponse, car il existe certains cas d'utilisation qui peuvent faire de Money un choix plus efficace que décimal, mais à moins qu'il y ait un cas très convaincant pour l'utiliser, je pense qu'il devrait être évité.
Nathan Griffiths
1
Bitcoin a 8 décimales. Vous ne pouvez même pas le stocker dans une moneycolonne
Panagiotis Kanavos
4

Tous les messages précédents apportent des points valables, mais certains ne répondent pas précisément à la question.

La question est la suivante: pourquoi quelqu'un préférerait-il l'argent alors que nous savons déjà qu'il s'agit d'un type de données moins précis et peut provoquer des erreurs s'il est utilisé dans des calculs complexes?

Vous utilisez de l'argent lorsque vous ne ferez pas de calculs complexes et pouvez échanger cette précision pour d'autres besoins.

Par exemple, lorsque vous n'avez pas à effectuer ces calculs et que vous devez importer des données à partir de chaînes de texte de devise valides. Cette conversion automatique fonctionne uniquement avec le type de données MONEY:

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

Je sais que vous pouvez créer votre propre routine d'importation. Mais parfois, vous ne voulez pas recréer une routine d'importation avec des formats régionaux spécifiques au monde.

Un autre exemple, lorsque vous n'avez pas à faire ces calculs (vous avez juste besoin de stocker une valeur) et que vous devez économiser 1 octet (l'argent prend 8 octets et la décimale (19,4) prend 9 octets). Dans certaines applications (CPU rapide, grande RAM, IO lente), comme la lecture d'une énorme quantité de données, cela peut aussi être plus rapide.

Weber K.
la source
2

Vous ne devez pas utiliser d'argent lorsque vous devez faire des multiplications / divisions sur la valeur. L'argent est stocké de la même manière qu'un entier est stocké, tandis que le nombre décimal est stocké sous la forme d'un point décimal et de chiffres décimaux. Cela signifie que l'argent perdra sa précision dans la plupart des cas, tandis que la décimale ne le fera que lorsqu'elle sera reconvertie à son échelle d'origine. L'argent est un point fixe, donc son échelle ne change pas pendant les calculs. Cependant, comme il s'agit d'un point fixe lorsqu'il est imprimé sous forme de chaîne décimale (par opposition à une position fixe dans une chaîne de base 2), les valeurs jusqu'à l'échelle de 4 sont représentées exactement. Donc, pour l'addition et la soustraction, l'argent va bien.

Une décimale est représentée en base 10 en interne, et donc la position du point décimal est également basée sur le nombre de base 10. Ce qui fait que sa partie fractionnaire représente exactement sa valeur, tout comme avec de l'argent. La différence est que les valeurs intermédiaires de décimales peuvent maintenir la précision jusqu'à 38 chiffres.

Avec un nombre à virgule flottante, la valeur est stockée en binaire comme s'il s'agissait d'un entier, et la position du point décimal (ou binaire, ahem) est relative aux bits représentant le nombre. Parce qu'il s'agit d'un point décimal binaire, les nombres en base 10 perdent leur précision juste après le point décimal. 1 / 5ème, ou 0,2, ne peut pas être représenté précisément de cette manière. Ni l'argent ni les décimales ne souffrent de cette limitation.

Il est assez facile de convertir de l'argent en décimal, d'effectuer les calculs, puis de stocker la valeur résultante dans un champ ou une variable monétaire.

De mon POV, je veux que les choses qui arrivent aux nombres se produisent sans avoir à trop y penser. Si tous les calculs vont être convertis en décimales, alors pour moi, je voudrais simplement utiliser des décimales. Je conserverais le champ de l'argent à des fins d'affichage.

En termes de taille, je ne vois pas assez de différence pour changer d'avis. L'argent prend 4 à 8 octets, tandis que la décimale peut être 5, 9, 13 et 17. Les 9 octets peuvent couvrir toute la plage que peuvent contenir les 8 octets. Par index (la comparaison et la recherche doivent être comparables).

Gerard ONeill
la source
Merci pour l'Upvote. Je regarde cela et pendant que j'obtiens ce que j'essayais de dire, je peux aussi voir que c'est très déroutant. Je vais peut-être le réécrire plus tard avec quelques exemples de bits vs décimaux.
Gerard ONeill
2

J'ai trouvé une raison d'utiliser la décimale sur l'argent dans le sujet de précision.

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

Testez-le et prenez votre décision.

QMaster
la source
2
Nous aimerions beaucoup entendre (lire, c'est-à-dire) votre conclusion.
Peter Mortensen
@PeterMortensen Je pense que si je veux avoir l'exhaustivité et la précision entre les types Money et Decimal, ma décision devrait être Décimal un.
QMaster
1
Pensez à mettre à jour votre réponse avec le résultat réel de ce qui précède. Ensuite, votre conclusion sera immédiatement évidente pour tous ceux qui liront :-)
Agreax
1
@Ageax Le résultat ajouté à la réponse.
QMaster
1

Je viens de voir cette entrée de blog: Money vs. Decimal dans SQL Server .

Ce qui dit essentiellement que l'argent a un problème de précision ...

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

set @m = 19.34
set @d = 19.34

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

Pour le moneytype, vous obtiendrez 19.30 au lieu de 19.34. Je ne sais pas s'il existe un scénario d'application qui divise l'argent en 1000 parties pour le calcul, mais cet exemple expose certaines limites.

Harsha
la source
15
Ce n'est pas un «problème», c'est «selon les spécifications»: «Les types de données moneyet smallmoneysont exacts au dix millième des unités monétaires qu'ils représentent.» comme indiqué dans msdn.microsoft.com/en-us/library/ms179882.aspx, donc quiconque dit "ce sont des ordures" ne sait pas de quoi il parle.
Albireo