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

?
Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top