Problème d'arrondi décimal automatique

11

La question est relativement simple. J'ai besoin de calculer 3 colonnes où les résultats moyens sont d'énormes décimales, et je rencontre un problème au début avec SQL Server arrondissant essentiellement les décimales indépendamment de toute conversion / conversion.

Par exemple, faisons une division simple comme 1234/1233. Une calculatrice produira 1 00081103000811. Mais quand je fais cela sur SQL Server, nous obtenons ce qui suit:

-- Result: rounded at 1.000811000... with trailing zeroes up until the 37 precision
SELECT CAST(CAST(1234 AS DEC(38,34))/CAST(1233 AS DEC(38,34)) AS DEC(38,37))

-- Result: rounded at 1.000811
SELECT CONVERT(DECIMAL(38,32), 1234)/CONVERT(DECIMAL(38,32),1233)

-- Correct result at 1,00081103000811
-- But this requires the zeroes to be put in manually when you don't
-- even know the precision of the end result
SELECT 1234.0/1233.00000000000000

Pourquoi cet arrondi automatique se produit-il? Et quelle est la meilleure façon de calculer des valeurs décimales incroyablement longues lorsque vous ne pouvez pas être sûr de la taille d'un nombre (la partie int ou dec), car la table peut contenir différentes valeurs différentes?

Merci!

Kahn
la source

Réponses:

17

tl; dr

Ne faites pas de calculs en langage SQL

Plus long

L'échelle et la précision des résultats sont bien définies ici sur MSDN . Ce n'est pas vraiment intuitif. Cependant, en termes simples, la précision est perdue lorsque les échelles d'entrée sont élevées car les échelles de résultat doivent être réduites à 38 avec une baisse de précision correspondante.

Pour confirmer les choses

  • Votre CAST supplémentaire dans le premier exemple ajoute simplement des zéros
  • La troncature se produit selon mon lien MSDN (2ème exemple)
  • Le 3ème exemple avec des constantes a impliqué des valeurs décimales qui sont juste suffisantes (5,1) et 18,14).
    Cela signifie que l'échelle de résultat et la précision n'ont pas de troncature (voir coup)

Plus d'informations sur les 1er et 3e cas ..

L'échelle des résultats pour une division est la suivante max(6, s1 + p2 + 1):

  • Premier exemple, c'est 77 qui est tombé à 38. La précision est forcée de la même manière, sous réserve d'un minimum de 6 (voir ceci )
  • Troisième exemple, c'est 24 donc la précision n'a pas besoin d'être ajustée

Vous avez quelques options

  • calculer dans le code client, par exemple .net
  • utiliser les fonctions CLR pour effectuer des calculs .net
  • vivre avec la perte de précision
  • utilisez le flotteur et vivez au mieux avec 15 personnages significatifs

Enfin, consultez ceci sur SO /programming/423925/t-sql-decimal-division-accuracy/424052#424052

gbn
la source
1

Je ne sais pas si cela aide, mais pour moi, ma colonne de la table temporaire a été définie sur décimal, je passais la conversion (décimal (15,2), 0,65) de l'insertion en temp_table. C'était un arrondi automatique, j'ai changé le type de colonne en décimal (16,2) pour correspondre à ce qui était passé. La table stocke maintenant 0,65.

natur3
la source
1

J'ai dû faire un travail autour. Voici ce que j'ai fait:

-----------------------------------
DECLARE @DENIED INT  = 33443
DECLARE @PAID INT = 148353
DECLARE @PCT Decimal (6,2)

SET @PCT = (@DENIED * 100.00 / @PAID)  -- Instead of dividing by 100, I included decimals

SELECT
@DENIED AS DEN
,@PAID AS PAID
,@PCT AS PCT

Résultats:

DEN PAID    PCT
-----   ----    -----
33443   148353  22.54   -- Instead of 22.00

J'espère que cela t'aides.

Manoj C
la source