Estoy usando una columna decimal para almacenar valores monetarios en una base de datos, y hoy me preguntaba qué precisión y escala usar.
Dado que las columnas supuestamente de un ancho fijo son más eficientes, estaba pensando que lo mismo podría ser cierto para las columnas decimales. ¿Lo es?
¿Y qué precisión y escala debo usar? Estaba pensando en precisión 24/8. ¿Es exagerado, no es suficiente o está bien?
Esto es lo que he decidido hacer:
- Almacene las tasas de conversión (cuando corresponda) en la propia tabla de transacciones, como flotante
- Almacenar la moneda en la tabla de la cuenta.
- El monto de la transacción será un
DECIMAL(19,4)
- Todos los cálculos que usan una tasa de conversión serán manejados por mi aplicación, así que mantengo el control de los problemas de redondeo
No creo que un problema para la tasa de conversión sea un problema, ya que es principalmente para referencia, y de todos modos lo convertiré a un decimal.
Gracias a todos por su valioso aporte.
DECIMAL(19, 4)
es una opción popular, verifique esto también marque aquí Formatos de moneda mundial para decidir cuántos lugares decimales usar, la esperanza ayuda.Respuestas:
Si está buscando una talla única, sugeriría que
DECIMAL(19, 4)
es una opción popular (un rápido Google lo confirma). Creo que esto se origina en el antiguo tipo de datos VBA / Access / Jet Currency, siendo el primer tipo decimal de punto fijo en el idioma;Decimal
solo vino en estilo 'versión 1.0' (es decir, no completamente implementado) en VB6 / VBA6 / Jet 4.0.La regla general para el almacenamiento de valores decimales de punto fijo es almacenar al menos un lugar decimal más del que realmente necesita para permitir el redondeo. Una de las razones para mapear el
Currency
tipo antiguo en el extremo frontal paraDECIMAL(19, 4)
escribir en el extremo posterior fue queCurrency
exhibía el redondeo de los banqueros por naturaleza, mientras que seDECIMAL(p, s)
redondeaba por truncamiento.Un espacio decimal adicional en el almacenamiento
DECIMAL
permite implementar un algoritmo de redondeo personalizado en lugar de tomar el valor predeterminado del proveedor (y el redondeo de los banqueros es alarmante, por decir lo menos, para un diseñador que espera que todos los valores que terminan en .5 se redondeen desde cero) .Sí, me
DECIMAL(24, 8)
parece una exageración. La mayoría de las monedas se cotizan con cuatro o cinco decimales. Sé de situaciones en las que se requiere una escala decimal de 8 (o más) pero aquí es donde se ha prorrateado una cantidad monetaria 'normal' (digamos cuatro decimales), lo que implica que la precisión decimal debe reducirse en consecuencia (también considere un tipo de coma flotante en tales circunstancias). Y nadie tiene tanto dinero hoy en día para requerir una precisión decimal de 24 :)Sin embargo, en lugar de un enfoque único para todos, algunas investigaciones pueden estar en orden. Pregúntele a su diseñador o experto en dominios sobre las reglas de contabilidad que pueden ser aplicables: PCGA, UE, etc. Recuerdo vagamente algunas transferencias dentro del estado de la UE con reglas explícitas para redondear a cinco decimales, por lo tanto, las uso
DECIMAL(p, 6)
para el almacenamiento. Los contadores generalmente parecen favorecer cuatro decimales.PD Evite el
MONEY
tipo de datos de SQL Server porque tiene serios problemas de precisión al redondear, entre otras consideraciones, como la portabilidad, etc. Consulte el blog de Aaron Bertrand .Microsoft y los diseñadores de idiomas eligieron el redondeo bancario porque los diseñadores de hardware lo eligieron [¿cita?]. Está consagrado en los estándares del Instituto de Ingenieros Eléctricos y Electrónicos (IEEE), por ejemplo. Y los diseñadores de hardware lo eligieron porque los matemáticos lo prefieren. Ver Wikipedia ; parafraseando: la edición de 1906 de Probabilidad y teoría de los errores llamó a esto "la regla de la computadora" ("computadoras", que significa humanos que realizan cálculos).
fuente
DECIMAL(19, 4)
más popular queDECIMAL(19, 2)
? La mayoría de las monedas mundiales son solo dos decimales.Recientemente implementamos un sistema que necesita manejar valores en múltiples monedas y convertir entre ellos, y descubrimos algunas cosas de la manera difícil.
NUNCA USE NÚMEROS DE PUNTO FLOTANTE PARA DINERO
La aritmética de punto flotante introduce imprecisiones que pueden no notarse hasta que hayan arruinado algo. Todos los valores deben almacenarse como enteros o tipos de decimales fijos, y si elige usar un tipo de decimales fijos, asegúrese de comprender exactamente qué hace ese tipo debajo del capó (es decir, usa internamente un número entero o coma flotante). tipo).
Cuando necesite hacer cálculos o conversiones:
Cuando convierta un número de coma flotante a un número entero en el paso 3, no solo lo eche: use una función matemática para redondearlo primero. Esto generalmente será
round
, aunque en casos especiales podría serfloor
oceil
. Conozca la diferencia y elija con cuidado.Almacene el tipo de un número junto al valor
Esto puede no ser tan importante para usted si solo maneja una moneda, pero fue importante para nosotros en el manejo de múltiples monedas. Utilizamos el código de 3 caracteres para una moneda, como USD, GBP, JPY, EUR, etc.
Dependiendo de la situación, también puede ser útil almacenar:
Conozca los límites de precisión de los números con los que está tratando
Para valores reales, desea ser tan preciso como la unidad más pequeña de la moneda. Esto significa que no tiene valores menores que un centavo, un centavo, un yen, un fen, etc. No almacene valores con mayor precisión que eso sin ninguna razón.
Internamente, puede optar por tratar con valores más pequeños, en cuyo caso ese es un tipo diferente de valor de moneda . Asegúrese de que su código sepa cuál es cuál y no los mezcla. Evite usar valores de coma flotante incluso aquí.
Sumando todas esas reglas juntas, decidimos las siguientes reglas. Al ejecutar el código, las monedas se almacenan utilizando un número entero para la unidad más pequeña.
En la base de datos, los valores se almacenan como una cadena en el siguiente formato:
Eso almacena el valor de $ 25.00. Pudimos hacer eso solo porque el código que se ocupa de las monedas no necesita estar dentro de la capa de la base de datos, por lo que todos los valores se pueden convertir en memoria primero. Sin duda, otras situaciones se prestarán a otras soluciones.
Y en caso de que no lo deje claro antes, ¡no use flotador!
fuente
bigint
si tuviera la intención de ordenar por la cantidad. Y no pierda su tiempo con PHP 32 bits cuando se trata de enteros grandes, actualice a 64 bits o Node.JS;)Cuando maneje dinero en MySQL, use DECIMAL (13,2) si conoce la precisión de sus valores de dinero o use DOUBLE si solo desea un valor aproximado rápido y suficientemente bueno. Entonces, si su aplicación necesita manejar valores monetarios de hasta un billón de dólares (o euros o libras), entonces esto debería funcionar:
O, si necesita cumplir con GAAP , use:
fuente
4 decimales le darían la precisión para almacenar las subunidades monetarias más pequeñas del mundo. Puede reducirlo aún más si necesita precisión de micropagos (¿nanopagos ?!).
Yo también prefiero los
DECIMAL
tipos de dinero específicos de DBMS, es más seguro mantener ese tipo de lógica en la aplicación IMO. Otro enfoque en la misma línea es simplemente usar un entero [largo], con formato en ¤unit.subunit para la legibilidad humana (¤ = símbolo de moneda) hecho a nivel de aplicación.fuente
El tipo de datos de dinero en SQL Server tiene cuatro dígitos después del decimal.
De los libros en línea de SQL Server 2000:
Los datos monetarios representan cantidades de dinero positivas o negativas. En Microsoft® SQL Server ™ 2000, los datos monetarios se almacenan utilizando los tipos de datos money y smallmoney. Los datos monetarios se pueden almacenar con una precisión de cuatro decimales. Use el tipo de datos de dinero para almacenar valores en el rango de -922,337,203,685,477.5808 a +922,337,203,685,477.5807 (requiere 8 bytes para almacenar un valor). Use el tipo de datos smallmoney para almacenar valores en el rango de -214,748.3648 a 214,748.3647 (requiere 4 bytes para almacenar un valor). Si se requiere un mayor número de lugares decimales, utilice el tipo de datos decimales.
fuente
A veces tendrá que ir a menos de un centavo y hay monedas internacionales que usan grandes demonios. Por ejemplo, puede cobrar a sus clientes 0,088 centavos por transacción. En mi base de datos Oracle, las columnas se definen como NUMBER (20,4)
fuente
Si va a realizar cualquier tipo de operaciones aritméticas en la base de datos (multiplicando las tasas de facturación, etc.), es probable que desee mucha más precisión de la que sugieren las personas aquí, por las mismas razones que nunca desea utilizar algo menos que un valor de coma flotante de doble precisión en el código de la aplicación.
fuente
BigDecimal
), pero durante mucho tiempo fue de doble precisión (pensar endouble
lugar defloat
). Además, la precisión arbitraria tiene importantes penalizaciones de rendimiento en algunos casos. La prueba es definitivamente el enfoque correcto.Si estuviera utilizando IBM Informix Dynamic Server, tendría un tipo de DINERO que es una variante menor en el tipo DECIMAL o NUMERIC. Siempre es un tipo de punto fijo (mientras que DECIMAL puede ser un tipo de punto flotante). Puede especificar una escala de 1 a 32 y una precisión de 0 a 32 (el valor predeterminado es una escala de 16 y una precisión de 2). Entonces, dependiendo de lo que necesite almacenar, puede usar DECIMAL (16,2), que aún es lo suficientemente grande como para mantener el Déficit Federal de EE. UU., Al centavo más cercano, o puede usar un rango más pequeño o más decimales.
fuente
Creo que, en gran parte, sus requisitos o los de su cliente deberían determinar qué precisión y escala utilizar. Por ejemplo, para el sitio web de comercio electrónico en el que estoy trabajando que trata con dinero solo en libras esterlinas, se me pidió que lo mantuviera en decimal (6, 2).
fuente
Una respuesta tardía aquí, pero he usado
que estoy en lo cierto al pensar que debería permitir hasta 99,999,999,999.99.
fuente