servidor SQL 2005 a perda de precisão numérica
-
02-07-2019 - |
Pergunta
A depuração algum código SQL finanças-relacionado encontrado um problema estranho com precisão numérica (24,8) matemática.
executando a seguinte consulta no seu MSSQL você obteria A + B * C resultado da expressão para ser 0,123457
Selecione um, B, C, A + B * C DE ( Select cast (0.12345678 como numérico (24,8)) como um, CAST (0 como numérico (24,8)) como B, CAST (500 como numérico (24,8)) como C ) T
Então nós perdemos 2 símbolos significativos. Tentando esta fixo de maneiras diferentes que eu tenho que a conversão do resultado da multiplicação intermediário (que é Zero!) Para numérico (24,8) iria funcionar bem.
E, finalmente, um tem uma solução. Mas eu ainda contamos com uma pergunta - por que se comporta MSSQL desta forma e qual o tipo conversões realmente ocorreu em minha amostra
?Solução
Assim como adição do tipo float é impreciso, a multiplicação dos tipos de decimais pode ser imprecisa (ou causa imprecisão) se você exceder a precisão. Consulte conversão de dados e decimal e numérico .
Uma vez que você multiplicado NUMERIC(24,8)
e NUMERIC(24,8)
, e SQL Server só irá verificar o tipo e não o conteúdo, ele provavelmente irá tentar salvar os potenciais 16 dígitos não decimais (24 - 8) quando ele não pode salvar todos os 48 dígitos do precisão (máximo é 38). Combine dois deles, você tem 32 dígitos não decimais, que deixa você com apenas 6 dígitos decimais (38 - 32)
Assim, a 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
reduz 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
Mais uma vez, entre NUMERIC(24,8)
e NUMERIC(38,6)
, SQL Server vai tentar salvar as potenciais 32 dígitos de não-decimais, de modo A + D
reduz a
SELECT CAST(0.12345678 AS NUMERIC(38,6))
que lhe dá 0.123457
após o arredondamento.
Outras dicas
Seguindo a lógica apontado por eed3si9n eo que você disse na sua pergunta, parece que a melhor abordagem ao fazer matemática operações é para extraí-los em uma função e, adicionalmente, para especificar a precisão após cada operação,
Neste caso, a função poderia 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
Apesar do que diz na Precision, Scale , e comprimento (Transact-SQL) . Creio que também está aplicando uma 'escala' (número de casas decimais) de 6 para o tipo NUMERIC resultando mínimo para multiplicação o mesmo que ele faz para a divisão etc.