Problema de arredondamento decimal automático

11

A questão é relativamente simples. Preciso calcular 3 colunas em que os resultados intermediários são decimais enormes e estou enfrentando um problema no início com o SQL Server basicamente arredondando os decimais, independentemente de qualquer conversão / conversão.

Por exemplo, vamos fazer uma divisão simples como 1234/1233. Uma calculadora produzirá 1.00081103000811. Mas quando faço isso no SQL Server, obtemos o seguinte:

-- Result: rounded at 1.000811000... with trailing zeroes up until the 37 precision
SELECT CAST(CAST(1234 AS DEC(38,34))/CAST(1233 AS DEC(38,34)) AS DEC(38,37))

-- Result: rounded at 1.000811
SELECT CONVERT(DECIMAL(38,32), 1234)/CONVERT(DECIMAL(38,32),1233)

-- Correct result at 1,00081103000811
-- But this requires the zeroes to be put in manually when you don't
-- even know the precision of the end result
SELECT 1234.0/1233.00000000000000

Por que esse arredondamento automático ocorre? E qual é a melhor maneira de calcular valores decimais insanamente longos quando você não tem certeza do tamanho de um número (a parte int ou dec), pois a tabela pode conter vários valores diferentes?

Obrigado!

Kahn
fonte

Respostas:

17

tl; dr

Não faça cálculos na linguagem SQL

Mais longo

A escala e a precisão dos resultados estão bem definidas aqui no MSDN . Na verdade, não é intuitivo. No entanto, em termos simples, a precisão é perdida quando as escalas de entrada são altas porque as escalas de resultados precisam ser reduzidas para 38 com uma queda de precisão correspondente.

Para confirmar as coisas

  • Seu CAST extra no primeiro exemplo simplesmente adiciona zeros
  • O truncamento acontece conforme meu link do MSDN (segundo exemplo)
  • O terceiro exemplo com constantes implica em valores decimais que são suficientes (5,1) e 18,14).
    Isso significa que a escala e a precisão dos resultados não têm truncamento (consulte a descrição)

Mais sobre os 1º e 3º casos.

A escala de resultados para uma divisão é max(6, s1 + p2 + 1):

  • Primeiro exemplo, este é 77, que caiu para 38. A precisão é reduzida de maneira semelhante, sujeita a um mínimo de 6 (veja isso )
  • Terceiro exemplo, este é 24, portanto a precisão não precisa ser ajustada

Você tem algumas opções

  • calcular no código do cliente, por exemplo, .net
  • use funções CLR para fazer cálculos .net
  • viva com a perda de precisão
  • use float e viva com 15 números significativos como melhor

Por fim, consulte isso no SO /programming/423925/t-sql-decimal-division-accuracy/424052#424052

gbn
fonte
1

Não tenho certeza se isso ajuda, mas para mim minha coluna da tabela temporária foi definida como decimal, eu estava passando o convert (decimal (15,2), 0,65) da inserção para temp_table. Este foi o arredondamento automático. Alterei o tipo de coluna para decimal (16,2) para corresponder ao que estava sendo passado. A tabela agora está armazenando 0,65.

natur3
fonte
1

Eu tive que fazer um trabalho. Aqui está o que eu fiz:

-----------------------------------
DECLARE @DENIED INT  = 33443
DECLARE @PAID INT = 148353
DECLARE @PCT Decimal (6,2)

SET @PCT = (@DENIED * 100.00 / @PAID)  -- Instead of dividing by 100, I included decimals

SELECT
@DENIED AS DEN
,@PAID AS PAID
,@PCT AS PCT

Resultados:

DEN PAID    PCT
-----   ----    -----
33443   148353  22.54   -- Instead of 22.00

Espero que isto ajude.

Manoj C
fonte