NUMERIC
/DECIMAL
Como dijo Joachim Isaksson
, desea usar NUMERIC
/DECIMAL
type, como un tipo de precisión arbitraria.
Dos puntos importantes sobre NUMERIC
/DECIMAL
:
- Lea el doc detenidamente para saber que debe especificar la escala para evitar la escala predeterminada de 0, es decir, valores enteros donde la fracción decimal se corta. Si bien este es uno de los lugares donde Postgres se desvía del SQL estándar (lo que le brinda una escala hasta el límite de implementación). Por lo tanto, no especificar la escala es una mala elección.
- Los tipos SQL
NUMERIC
&DECIMAL
son cercanos pero no idénticos según el estándar SQL. En SQL:92 , su precisión especificada paraNUMERIC
se respeta, mientras que paraDECIMAL
el servidor de la base de datos puede agregar precisión adicional más allá de lo que especificó. Aquí nuevamente, Postgres se desvía un poco del estándar, con ambosNUMERIC
&DECIMAL
documentado como equivalente.
Términos:
- La precisión es el número total de dígitos en un número.
- La escala es el número de dígitos a la derecha del punto decimal (la fracción decimal).
- ( Precisión - Escala ) =Número de dígitos a la izquierda del punto decimal (parte entera).
Sea claro en las especificaciones de precisión y escala de su proyecto:
- Grande
La precisión debe ser lo suficientemente grande para manejar números más grandes que puedan ser necesarios en el futuro. Es decir... Tal vez su aplicación funcione hoy en cantidades de miles de dólares, pero en el futuro deberá realizar informes acumulativos que terminen en millones. - Pequeño
Para algunos fines contables, es posible que deba almacenar una fracción de la cantidad de moneda más pequeña. Es decir… Más de 3 o 4 decimales en lugar de los 2 necesarios para un centavo en USD .
Evite MONEY
escribir
Postgres ofrece un MONEY
tipo también. Eso puede sonar bien, pero probablemente no sea lo mejor para la mayoría de los propósitos. Una desventaja es que con MONEY
la escala se establece mediante una configuración de toda la base de datos basado en locale
. Por lo tanto, esa configuración puede variar peligrosamente fácilmente cuando cambia de servidor o realiza otros cambios. Además, no puede controlar esa configuración para columnas específicas, mientras que puede establecer la escala en cada columna de NUMERIC
escribe. Por último, MONEY
no es SQL estándar como se muestra en esta lista de datos SQL estándar tipos
. Postgres incluye MONEY
para la comodidad de las personas que transfieren datos de otros sistemas de bases de datos.
Mover el punto decimal
Otra alternativa empleada por algunos es mover el punto decimal y simplemente almacenarlo en un tipo de datos entero grande.
Por ejemplo, si almacena USD dólares al centavo, multiplique cualquier número fraccionario dado por 100, convierta a un tipo entero y continúe. Por ejemplo, $123,45 se convierte en el número entero 12 345.
El beneficio de este enfoque es tiempos de ejecución más rápidos. Operaciones como sum
son muy rápidos cuando se realizan en números enteros. Otro beneficio de los números enteros es un menor uso de memoria.
Encuentro este enfoque molesto, confuso y arriesgado. Molesto porque las computadoras deberían estar trabajando para nosotros, no contra nosotros. Arriesgado porque algún programador o usuario puede olvidarse de multiplicar/dividir para convertir de nuevo a número fraccionario, dando resultados incorrectos. Si trabaja en un sistema sin un buen soporte para números fraccionarios precisos, este enfoque podría ser una solución alternativa aceptable.
No veo ninguna ventaja en mover el punto decimal cuando tenemos DECIMAL
/NUMERIC
en SQL y BigDecimal
en Java.
Redondeo y NaN
En la programación de su aplicación, así como en cualquier cálculo realizado en el lado del servidor de Postgres, tenga mucho cuidado y tenga cuidado con el redondeo y el truncamiento. en la fracción decimal. Y prueba para NaNs involuntarios apareciendo.
En ambos lados, aplicación y Postgres, siempre evite punto flotante tipos de datos para el trabajo de dinero. El punto flotante está diseñado para velocidad de rendimiento , pero a costa del costo de precisión . Los cálculos pueden resultar en dígitos adicionales aparentemente locos en la fracción decimal. No es bueno para fines financieros/dinero u otros fines donde la precisión es importante.
BigDecimal
Sí, en Java, desea BigDecimal
como su tipo de precisión arbitraria. BigDecimal
es más lento y utiliza más memoria, pero almacenará con precisión las cantidades de dinero. SQL NUMERIC
/DECIMAL
debe asignarse a BigDecimal
como se comenta aquí
y en StackOverflow
.
BigDecimal
es una de las mejores cosas de Java. No conozco ninguna otra plataforma con una clase similar, especialmente una tan bien implementada y perfeccionada con importantes mejoras y correcciones realizadas a lo largo de los años.
Usando BigDecimal
es definitivamente más lento que usar los tipos de punto flotante de Java
, float
&double
. Pero en las aplicaciones del mundo real, dudo que sus cálculos de dinero sean un cuello de botella. Y además, qué es lo que tú o tus clientes queréis:el más rápido cálculos de dinero, o precisos calculos de dinero? 😉
Siempre he pensado en BigDecimal
como la función durmiente más grande en Java, la ventaja más importante de usar la plataforma Java sobre tantas otras plataformas que carecen de un soporte tan sofisticado para números fraccionarios.
Pregunta similar:Mejor tipo de datos para moneda