type tipos ejemplo declarar datos data sql-server floating-point type-conversion casting floating-accuracy

tipos - Pérdida de precisión numérica de SQL Server 2005



tipos de datos en sql server 2014 (3)

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

Al ejecutar la siguiente consulta en su MSSQL obtendría un resultado de expresión A + B * C de 0.123457

SELECCIONE A, B, C, A + B * C FROM (SELECT CAST (0.12345678 COMO NUMÉRICO (24,8)) COMO A, CAST (0 COMO NUMÉRICO (24,8)) COMO B, CAST (500 COMO NUMÉRICO (24) , 8)) AS C) T

Así que hemos perdido 2 símbolos significativos. Al tratar 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 tienes 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?


A pesar de lo que dice sobre Precisión, Escala y Longitud (Transact-SQL) . Creo que también está aplicando una "escala" mínima (número de decimales) de 6 al tipo NÚMERO resultante para la multiplicación, al igual que para la división, etc.


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. Vea Conversión de tipo de datos y decimal y numérico .

Dado que multiplicó NUMERIC(24,8) y NUMERIC(24,8) , y SQL Server solo verificará el tipo, no el contenido, probablemente intente guardar los posibles 16 dígitos no decimales (24 - 8) cuando sea posible. Guarde 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).

Por lo tanto, la consulta 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

De nuevo, entre NUMERIC(24,8) y NUMERIC(38,6) , SQL Server intentará guardar los posibles 32 dígitos de los no decimales, por lo que A + D reduce a

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

que te da 0.123457 después del redondeo.


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

En este caso, la función podría ser algo así 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