Problema de redondeo decimal automático

11

La pregunta es relativamente simple. Necesito calcular 3 columnas donde los resultados intermedios son decimales enormes, y me encuentro con un problema temprano con SQL Server básicamente redondeando los decimales independientemente de cualquier conversión / conversión.

Por ejemplo, hagamos una división simple como 1234/1233. Una calculadora producirá 1,00081103000811. Pero cuando hago esto en SQL Server, obtenemos lo siguiente:

-- 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 qué ocurre este redondeo automático? ¿Y cuál es la mejor manera de calcular valores decimales increíblemente largos cuando no puede estar seguro de qué tan grande será un número (la parte int o dec), ya que la tabla puede contener varios valores diferentes?

¡Gracias!

Kahn
fuente

Respuestas:

17

tl; dr

No hagas cálculos en lenguaje SQL

Más

La escala de resultados y la precisión están bien definidos aquí en MSDN . No es intuitivo, de verdad. Sin embargo, en términos simples, la precisión se pierde cuando las escalas de entrada son altas porque las escalas de resultados deben reducirse a 38 con una caída de precisión coincidente.

Para confirmar las cosas

  • Su CAST extra en el primer ejemplo simplemente agrega ceros
  • El truncamiento ocurre según mi enlace MSDN (segundo ejemplo)
  • El tercer ejemplo con constantes tiene valores decimales implícitos que son suficientes (5,1) y 18,14).
    Esto significa que la escala de resultados y la precisión no tienen truncamiento (ver golpe)

Más sobre los casos primero y tercero.

La escala de resultados para una división es max(6, s1 + p2 + 1):

  • Primer ejemplo, esto es 77, que se redujo a 38. La precisión se reduce de manera similar, sujeto a un mínimo de 6 (ver esto )
  • Tercer ejemplo, esto es 24, por lo que no es necesario ajustar la precisión

Tienes algunas opciones

  • calcular en el código del cliente, por ejemplo .net
  • usar funciones CLR para hacer cálculos .net
  • vivir con la pérdida de precisión
  • usa flotador y vive con 15 figuras significativas como mejor

Finalmente, vea esto en SO /programming/423925/t-sql-decimal-division-accuracy/424052#424052

gbn
fuente
1

No estoy seguro de si esto ayuda, pero para mí la columna de la tabla temporal estaba configurada en decimal, estaba pasando convert (decimal (15,2), 0.65) de la inserción a temp_table. Este fue el redondeo automático, cambié el tipo de columna a decimal (16,2) para que coincida con lo que se estaba pasando. La tabla ahora está almacenando 0.65.

natur3
fuente
1

Tuve que hacer un trabajo alrededor. Esto es lo que hice:

-----------------------------------
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 esto ayude.

Manoj C
fuente