5

La depuración de algún código SQL relacionado con las finanzas encontró un problema extraño con la precisión matemática numérica (24,8).SQL Server 2005 pérdida de precisión numérica

Ejecutar la siguiente consulta en su MSSQL se obtendría un resultado de la expresión * C + B para ser 0.123457

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

Así hemos perdido 2 símbolos significativos Tratando de arreglar esto de diferentes maneras, conseguí que la conversión del resultado de multiplicación intermedio (que es cero) a numérico (24,8) funcionara bien.

Y finalmente tenemos una solución. Pero aún tengo una pregunta: ¿por qué MSSQL se comporta de esta manera y qué tipo de conversiones ocurrieron realmente en mi muestra?

Respuesta

7

Así como la adición del tipo de letra flotante es incorrecta, la multiplicación de los tipos de decimales puede ser inexacta (o causar inexactitudes) si excede la precisión. Ver Data Type Conversion y decimal and numeric.

Dado que multiplicó NUMERIC(24,8) y NUMERIC(24,8), y SQL Server solo verificará el tipo y no el contenido, probablemente intente guardar los posibles 16 dígitos no decimales (24 - 8) cuando no pueda guardar los 48 dígitos de precisión (max es 38). Combina dos de ellos, obtienes 32 dígitos no decimales, lo que te deja con solo 6 dígitos decimales (38 - 32).

Así, la búsqueda original

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 

reduce a

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 

Una vez más, entre NUMERIC(24,8) y NUMERIC(38,6), SQL Server tratará de salvar a los potenciales 32 dígitos de los no decimales, por lo A + D se reduce a

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

que gi te ves 0.123457 después del redondeo.

+0

¿quisiste decir NUMERIC (32,6)) ?? Si la suma debe ser 38 – Edmondo1984

+0

@ Edmondo1984 Lea los enlaces y comprenda lo que significan ambos números. –

+0

Usted dice que al multiplicar dos números (24,8) el servidor intentará guardar 16 bits y producir un (32,6), ¿cómo se convierte en un 38,6?Gracias – Edmondo1984

0

Siguiendo la lógica señalado por eed3si9n y lo que ha dicho en su pregunta parece que el mejor enfoque al hacer matemáticas operaciones es extraerlos en una función y, además, para especificar la precisión después de cada operación,

Es este caso, la función podría ser algo como:

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

Ese enfoque puede no resolver el problema de SQL Server cortando las partes decimales. Para guardar las partes decimales, puede ser necesario convertir a @a y @b en dobles. –

+0

Gracias, lo tendré en cuenta cuando trabaje en algunas matemáticas de precisión en SQL, hasta ahora no he tenido que usarlo, pero ahora es bueno que haya algunos problemas que considerar – kristof

Cuestiones relacionadas