5

Le débogage de certains codes SQL liés à la finance a trouvé un problème étrange avec la précision mathématique numérique (24,8).SQL Server 2005 perte de précision numérique

L'exécution de la requête suivante sur votre MSSQL vous obtenez A + B * Résultat d'expression C pour être 0,123457

SELECT A, B, C, A + B * C DE ( SELECT CAST (0.12345678 AS NUMERIC (24,8)) AS A, CAST (0 AS NUMERIC (24,8)) AS B, CAST (500 AS NUMERIC (24,8)) AS C ) T

Ainsi nous avons perdu 2 symboles significatifs. Essayer d'obtenir ceci fixé de différentes manières j'ai obtenu que la conversion du résultat intermédiaire de multiplication (qui est Zéro!) En numérique (24,8) fonctionnerait bien.

Et enfin une solution. Mais j'ai encore une question - pourquoi MSSQL se comporte de cette façon et quelles conversions de type ont réellement eu lieu dans mon échantillon?

Répondre

7

Tout comme l'ajout du type flottant est inexact, la multiplication des types décimaux peut être inexacte (ou entraîner une imprécision) si vous dépassez la précision. Voir Data Type Conversion et decimal and numeric. Etant donné que vous avez multiplié NUMERIC(24,8) et NUMERIC(24,8), et que SQL Server ne vérifiera que le type et non le contenu, il essaiera probablement d'enregistrer les 16 chiffres non décimaux potentiels (24 - 8) lorsqu'il ne peut pas enregistrer tous les 48 chiffres de précision (max 38). Combinez deux d'entre eux, vous obtenez 32 chiffres non décimaux, ce qui vous laisse avec seulement 6 chiffres décimaux (38 - 32).

Ainsi, la requête initiale

SELECT A, B, C, A + B * C 
FROM (SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A, 
    CAST(0 AS NUMERIC(24,8)) AS B, 
    CAST(500 AS NUMERIC(24,8)) AS C) T 

réduit à

SELECT A, B, C, A + D 
FROM (SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A, 
    CAST(0 AS NUMERIC(24,8)) AS B, 
    CAST(500 AS NUMERIC(24,8)) AS C, 
    CAST(0 AS NUMERIC(38,6)) AS D) T 

Encore une fois, entre NUMERIC(24,8) et NUMERIC(38,6), SQL Server va essayer de sauver les 32 potentiels chiffres non décimales, donc A + D réduit à

SELECT CAST(0.12345678 AS NUMERIC(38,6)) 

qui gi ves vous 0.123457 après arrondi.

+0

voulez-vous dire NUMERIC (32,6)) ?? Si la somme doit être 38 – Edmondo1984

+0

@ Edmondo1984 Veuillez lire les liens et comprendre ce que les deux nombres signifient. –

+0

Vous dites que lorsque vous multipliez deux numériques (24,8) le serveur essaiera d'enregistrer 16 bits et de produire un (32,6), comment cela devient-il un 38,6?Merci – Edmondo1984

0

Suivant la logique a souligné par eed3si9n et ce que vous avez dit dans votre question, il semble que la meilleure approche pour faire des opérations mathématiques est de les extraire en fonction et en plus de spécifier la précision après chaque opération,

Il présente Si la fonction pourrait ressembler à:

create function dbo.myMath(@a as numeric(24,8), @b as numeric(24,8), @c as numeric(24,8)) 
returns numeric(24,8) 
as 
begin 
    declare @d as numeric(24,8) 
    set @d = @b* @c 
    return @a + @d 
end 
+0

Cette approche ne peut pas résoudre le problème de SQL Server découpant les parties décimales. Pour enregistrer les parties décimales, il peut être nécessaire de convertir en @a et @b en double. –

+0

Merci, je vais le garder à l'esprit lorsque vous travaillez sur des maths de précision en SQL, jusqu'à présent, je n'ai pas besoin de l'utiliser mais il est bon maintenant qu'il puisse y avoir quelques problèmes à considérer – kristof