El mejor tipo de datos para almacenar valores de moneda en una base de datos MySQL

Respuestas:

227

Algo así Decimal(19,4)generalmente funciona bastante bien en la mayoría de los casos. Puede ajustar la escala y la precisión para adaptarse a las necesidades de los números que necesita almacenar. Incluso en SQL Server, tiendo a no usar " money" porque no es estándar.

Kibbee
fuente
52
Un punto sobre el tamaño: según MSDN ( msdn.microsoft.com/en-us/library/ms187746.aspx ), Decimal (10,4) y Decimal (19,4) ambos usan 9 bytes de almacenamiento, por lo que podría bien primavera para esos 9 dígitos adicionales de escala.
Adam Nofsinger
1
El artículo de MSDN trata sobre SQL Server, pero la pregunta es sobre MySQL. (Me he reunido con desarrolladores que piensan que ambos son lo mismo, así que es mejor ser claro)
Cja
55
¿Cuál es el beneficio de usar en (19,4)lugar de (19,2)?
ryvantage
1
Mi beneficio fue este ... necesitaba todas las filas de mi tabla para igualar una cantidad particular de dinero. Digamos que la cantidad es de $ 10.00. A medida que se agregan nuevas filas, cada cantidad de fila cambia. Si hay 3 filas en la tabla. 10/3 = 3.3333333333 ... pero con solo 2 decimales se almacenan como 3.33. Entonces, cuando los sumas, 3.33 + 3.33 + 3.33 = 9.99. Perdimos un centavo! Se pone aún peor en un conjunto de datos más grande. Almacene a 19,4 y sume sus totales, luego redondee la salida a 19,2 ..
Rick
49

Lo único que debe tener en cuenta es que si migra de una base de datos a otra, puede encontrar que DECIMAL (19,4) y DECIMAL (19,4) significan cosas diferentes

( http://dev.mysql.com/doc/refman/5.1/en/precision-math-decimal-changes.html )

    DBASE: 10,5 (10 enteros, 5 decimales)
    MYSQL: 15,5 (15 dígitos, 10 enteros (15-5), 5 decimales)
SeanJA
fuente
Link ahora está muerto, desafortunadamente.
Marco Aurélio Deleu
1
@ MarcoAurélioDeleu: he cambiado el enlace para que apunte a la página de Wayback Machine, para que pueda verlo tal como se vio en 2009.
Tony
17

También es importante calcular cuántos decimales pueden ser necesarios para sus cálculos.

Trabajé en una aplicación de precio de acciones que requería el cálculo del precio de un millón de acciones. El precio de la acción cotizada tuvo que almacenarse con 7 dígitos de precisión.

Leah
fuente
77
Es un buen punto, especialmente en aplicaciones financieras, el "precio" ciertamente no implica "dinero"
Mike Woodhouse
17

La respuesta de Assaf de

Depende de cuánto dinero tienes ...

Suena frívolo, pero en realidad es pertinente.

Solo hoy tuvimos un problema en el que no se pudo insertar un registro en nuestra tabla de tarifas, porque una de las columnas (GrossRate) está configurada en decimal (11,4), y nuestro departamento de productos acaba de obtener un contrato para habitaciones en algún resort increíble en Bora Bora, que se venden por varios millones de francos del Pacífico por noche ... algo que nunca se anticipó cuando el esquema de la base de datos se diseñó hace 10 años.

Scott Ferguson
fuente
2
Es por eso que recomendé decimal (19,4). Puede parecer excesivo, pero nunca se sabe cuándo necesitará almacenar una cantidad realmente grande en ese campo.
Kibbee
2
@Kibbee: No habría estado de acuerdo con usted para nuestros requisitos hasta hoy. (Durante 6 años (11,4) estuvo perfectamente bien ...)
Scott Ferguson
@Kibbee Esto suena como un meme de 640 Kb :)
Nikita Bosik
13

Para las aplicaciones de contabilidad es muy común almacenar los valores como enteros (algunos incluso llegan a decir que es la única forma). Para tener una idea, tome el monto de las transacciones (supongamos $ 100.23) y multiplique por 100, 1000, 10000, etc. para obtener la precisión que necesita. Entonces, si solo necesita almacenar centavos y puede redondear hacia arriba o hacia abajo de manera segura, simplemente multiplique por 100. En mi ejemplo, eso haría que 10023 sea el número entero para almacenar. Ahorrará espacio en la base de datos y comparar dos enteros es mucho más fácil que comparar dos flotantes. Mis $ 0.02.

Dane Bendixen
fuente
¿Cómo se almacena 6.125 (6 1/8)?
PeterToTheThird
Supongo que lo almacenaría como un número entero 6125.
Jimmy Knoot
2
¿Cómo sería esto mejor que DECIMAL? Debería tener mucho cuidado al traducir siempre centavos, molinos o molinos a dólares, en los momentos apropiados.
He leído que el rendimiento suele ser más rápido con INT que DECIMAL, incluso en las últimas versiones de MySQL. También es más fácil cuando necesita llevar estos valores a PHP o algo así y comparar valores.
Dane Bendixen
9

entrada súper tardía pero GAAP es una buena regla general.

Si su aplicación necesita manejar valores monetarios de hasta un billón, esto debería funcionar: 13,2 Si necesita cumplir con los GAAP (Principios de contabilidad generalmente aceptados), use: 13,4

Por lo general, debe sumar sus valores monetarios en 13,4 antes de redondear la salida a 13,2.

Fuente: Mejor tipo de datos para almacenar valor monetario en MySQL

Damian
fuente
5

Podría usar algo como DECIMAL(19,2)por defecto para todos sus valores monetarios, pero si alguna vez solo almacena valores inferiores a $ 1,000, eso será un desperdicio de valioso espacio en la base de datos.

Para la mayoría de las implementaciones, DECIMAL(N,2)sería suficiente, donde el valor de Nes al menos el número de dígitos antes .de la mayor suma que alguna vez espere que se almacene en ese campo + 5. Entonces, si nunca espera almacenar valores superiores a 999999.99, DECIMAL(11,2)debería ser más que suficiente (hasta que las expectativas cambien).

Si desea cumplir con los GAAP , puede ir con DECIMAL(N,4), donde el valor de Nes al menos el número de dígitos antes .de la mayor suma que espera que se almacene en ese campo + 7.

John Slegers
fuente
3

Depende de la naturaleza de los datos. Necesitas contemplarlo de antemano.

Mi caso

  • decimal (13,4) sin firmar para registrar transacciones de dinero
    • almacenamiento eficiente (4 bytes para cada lado del punto decimal de todos modos) 1
    • GAAP compatible
  • decimal (19,4) sin signo para agregados
    • necesitamos más espacio para un total de múltiples transacciones multimillonarias
    • semi-cumplimiento con el tipo de datos MS Currency no dañará 2
    • ocupará más espacio por registro (11 bytes - 7 a la izquierda y 4 a la derecha), pero esto está bien ya que hay menos registros para los agregados 1
  • decimal (10,5) para los tipos de cambio
    • normalmente se citan con 5 dígitos en total para que pueda encontrar valores como 1.2345 y 12.345 pero no 12345.67890
    • es una convención generalizada, pero no un estándar codificado (al menos para mi conocimiento de búsqueda rápida)
    • puede hacerlo decimal (18,9) con el mismo almacenamiento, pero las restricciones de tipo de datos son un valioso mecanismo de validación incorporado

¿Por qué (M, 4)?

  • hay monedas que se dividen en mil centavos
  • hay equivalentes de dinero como "Unidad de Fermento", "CLF" expresado con 4 decimales significativos 3 , 4
  • cumple con GAAP

Compensación

  • menor precisión:
    • menor costo de almacenamiento
    • cálculos más rápidos
    • menor riesgo de error de cálculo
    • copia de seguridad y restauración más rápidas
  • mayor precisión:
    • compatibilidad futura (los números tienden a crecer)
    • ahorro de tiempo de desarrollo (no tendrá que reconstruir medio sistema cuando se cumplan los límites)
    • menor riesgo de fallas en la producción debido a una precisión de almacenamiento insuficiente

Extremo compatible

Si bien MySQL le permite usar el decimal (65,30), 31 para la escala y 30 para la precisión parecen ser nuestros límites si queremos dejar abierta la opción de transferencia.

Máxima escala y precisión en los RDBMS más comunes:

            Escala de precisión
Oráculo 31 31
T-SQL 38 38
MySQL 65 30
PostgreSQL 131072 16383

6 , 7 , 8 , 9

Razonable Extremo

  1. ¿Por qué (27,4)?
    • nunca se sabe cuando el sistema necesita almacenar dólares zimbabuenses

Septiembre de 2015 El gobierno de Zimbabwe declaró que cambiaría dólares de Zimbabwe por dólares estadounidenses a una tasa de 1 USD a 35 billones de dólares de Zimbabwe 5

Tendemos a decir "sí, claro ... no necesitaré esas figuras locas". Bueno, los zimbabuenses solían decir eso también. No hace mucho tiempo.

Imaginemos que necesita registrar una transacción de 1 millón de dólares en dólares zimbabuenses (tal vez sea poco probable hoy, pero ¿quién sabe cómo será esto dentro de 10 años a partir de ahora?).

  1. (1 millón USD) * (35 Quadrylion ZWL) = (10 ^ 6) * (35 * 10 ^ 15) = 35 * 10 ^ 21
  2. nosotros necesitamos:
    • 2 dígitos para almacenar "35"
    • 21 dígitos para almacenar los ceros
    • 4 dígitos a la derecha del punto decimal
  3. esto hace decimal (27,4) que nos cuesta 15 bytes por cada entrada
  4. podemos agregar un dígito más a la izquierda sin costo alguno; tenemos decimal (28,4) para 15 bytes
  5. Ahora podemos almacenar 10 millones de transacciones en dólares estadounidenses expresadas en dólares zimbabuenses, o asegurarnos de otro ataque de hiperinflación, que con suerte no sucederá.
kshishkin
fuente
0

Aunque esto puede ser tarde, pero será útil para alguien más. De mi experiencia e investigación he llegado a conocer y aceptar el decimal (19, 6). Eso es cuando trabajo con php y mysql. cuando se trabaja con gran cantidad de dinero y tipo de cambio

precioso
fuente