¿Debería elegir los tipos de datos MONEY o DECIMAL (x, y) en SQL Server?

Tengo curiosidad acerca de si existe o no una diferencia real entre el tipo de datos del money y algo así como el decimal(19,4) (que es lo que el dinero usa internamente, creo).

Soy consciente de que el money es específico de SQL Server. Quiero saber si hay una razón de peso para elegir una sobre la otra; la mayoría de los ejemplos de SQL Server (p. ej., la base de datos AdventureWorks) usan money y no datos decimal como información sobre precios.

¿Debo seguir usando el tipo de datos money, o hay algún beneficio de usar decimal en su lugar? El dinero tiene menos caracteres para escribir, pero esa no es una razón válida 🙂

Nunca debes usar dinero. No es preciso, y es pura basura; siempre use decimal / numérico.

Ejecuta esto para ver lo que quiero decir:

 DECLARE @mon1 MONEY, @mon2 MONEY, @mon3 MONEY, @mon4 MONEY, @num1 DECIMAL(19,4), @num2 DECIMAL(19,4), @num3 DECIMAL(19,4), @num4 DECIMAL(19,4) SELECT @mon1 = 100, @mon2 = 339, @mon3 = 10000, @num1 = 100, @num2 = 339, @num3 = 10000 SET @mon4 = @mon1/@mon2*@mon3 SET @num4 = @num1/@num2*@num3 SELECT @mon4 AS moneyresult, @num4 AS numericresult 

Salida: 2949.0000 2949.8525

Para algunas de las personas que dijeron que no divide el dinero por dinero:

Esta es una de mis consultas para calcular correlaciones, y cambiar eso a dinero da resultados incorrectos.

 select t1.index_id,t2.index_id,(avg(t1.monret*t2.monret) -(avg(t1.monret) * avg(t2.monret))) /((sqrt(avg(square(t1.monret)) - square(avg(t1.monret)))) *(sqrt(avg(square(t2.monret)) - square(avg(t2.monret))))), current_timestamp,@MaxDate from Table1 t1 join Table1 t2 on t1.Date = traDate group by t1.index_id,t2.index_id 

SQLMenace dijo que el dinero es inexacto. ¡Pero no multiplicas / divides dinero por dinero! ¿Cuánto cuesta 3 dólares por 50 centavos? 150 dolares? Usted multiplica / divide dinero por escalares, que deberían ser decimales.

 DECLARE @mon1 MONEY, @mon4 MONEY, @num1 DECIMAL(19,4), @num2 DECIMAL(19,4), @num3 DECIMAL(19,4), @num4 DECIMAL(19,4) SELECT @mon1 = 100, @num1 = 100, @num2 = 339, @num3 = 10000 SET @mon4 = @mon1/@num2*@num3 SET @num4 = @num1/@num2*@num3 SELECT @mon4 AS moneyresult, @num4 AS numericresult 

Resultados en el resultado correcto:

  resultado numérico de moneyresult
 --------------------- ----------------------------- ----------
 2949.8525 2949.8525 

money es bueno siempre que no necesite más de 4 dígitos decimales, y se asegura de que sus escalares, que no representan dinero, sean decimal .

Todo es peligroso si no sabes lo que estás haciendo

Incluso los tipos decimales de alta precisión no pueden salvar el día:

 declare @num1 numeric(38,22) declare @num2 numeric(38,22) set @num1 = .0000006 set @num2 = 1.0 select @num1 * @num2 * 1000000 

1.000000 <- Debería ser 0.6000000


Los tipos de money son enteros

Las representaciones de texto de smallmoney y decimal(10,4) pueden parecerse, pero eso no las hace intercambiables. ¿Se encoge cuando ve las fechas almacenadas como varchar(10) ? Esta es la misma cosa

Detrás de las escenas, money / smallmoney son solo bigint / int El punto decimal en la representación de texto de money es visual fluff, al igual que los guiones en una fecha aaaa-mm-dd. SQL en realidad no almacena esos internamente.

Con respecto al decimal frente al money , elija lo que sea apropiado para sus necesidades. Los tipos de money existen porque el almacenamiento de valores contables como múltiplos enteros de 1/10000 de unidad es muy común. Además, si está lidiando con dinero real y cálculos más allá de la simple sum y resta, ¡no debería estar haciendo eso a nivel de la base de datos! Hazlo a nivel de aplicación con una biblioteca que admita el Redondeo Bancario (IEEE 754)

Me doy cuenta de que WayneM ha declarado que sabe que el dinero es específico de SQL Server. Sin embargo, él pregunta si hay alguna razón para usar el dinero en vez de decimal o viceversa y creo que una razón obvia todavía debe ser establecida y que usar decimal significa que es una cosa menos de la que preocuparse si alguna vez tiene que cambiar su DBMS – que puede suceder

¡Haga que sus sistemas sean lo más flexibles posible!

Bueno, ¡me gusta el MONEY ! Es un byte más barato que DECIMAL , y los cálculos se realizan más rápido porque (debajo de las coberturas) las operaciones de sum y resta son esencialmente operaciones enteras. El ejemplo de @ SQLMenace, que es una gran advertencia para los desconocedores, podría aplicarse igualmente a los egers INT , donde el resultado sería cero. Pero esa no es una razón para no usar números enteros, cuando corresponda .

Entonces, es perfectamente “seguro” y apropiado usar MONEY cuando lo que está tratando es MONEY y usarlo de acuerdo con las reglas matemáticas que sigue (igual que INT eger).

¿Hubiera sido mejor si SQL Server promoviera la división y la multiplicación de MONEY en DECIMAL s (o FLOAT s?) – posiblemente, pero no eligieron hacer esto; Tampoco eligieron promover Egers INT para FLOTAR al dividirlos.

MONEY no tiene problemas de precisión; que DECIMAL obtenga un tipo intermedio más grande utilizado durante los cálculos es solo una ‘característica’ de usar ese tipo (y no estoy seguro de hasta qué punto se extiende esa ‘característica’).

Para responder a la pregunta específica, ¿una “razón convincente”? Bueno, si quieres un rendimiento máximo absoluto en una SUM(x) donde x podría ser DECIMAL o MONEY , entonces MONEY tendrá una ventaja.

Además, no olvides que es un primo más pequeño, SMALLMONEY 4 bytes, pero tiene un máximo de 214,748.3647 , que es muy poco por dinero, y por lo tanto no suele ser una buena opción.

Para demostrar el punto en torno al uso de tipos intermedios más grandes, si asigna el intermedio explícitamente a una variable, DECIMAL sufre el mismo problema:

 declare @a decimal(19,4) declare @b decimal(19,4) declare @c decimal(19,4) declare @d decimal(19,4) select @a = 100, @b = 339, @c = 10000 set @d = @a/@b set @d = @d*@c select @d 

Produce 2950.0000 (está bien, entonces al menos DECIMAL redondeado en lugar de MONEY truncado, lo mismo que un entero).

Como un punto contrario al empuje general de las otras respuestas. Vea Los muchos beneficios del dinero … ¡Tipo de datos! en la guía de SQLCAT para motor relacional

Específicamente señalaría lo siguiente

Al trabajar en implementaciones de clientes, encontramos algunos números de rendimiento interesantes sobre el tipo de datos de dinero. Por ejemplo, cuando Analysis Services se estableció en el tipo de datos de moneda (desde el doble) para que coincida con el tipo de datos monetarios de SQL Server, hubo una mejora del 13% en la velocidad de procesamiento (filas / seg). Para obtener un rendimiento más rápido dentro de SQL Server Integration Services (SSIS) para cargar 1.18 TB en menos de treinta minutos, como se indica en SSIS 2008 – rendimiento ETL del récord mundial, se observó que el cambio de las cuatro columnas decimales (9,2) con un tamaño de 5 bytes en la tabla TPC-H LINEITEM a dinero (8 bytes) mejora la velocidad de inserción masiva en un 20% … La razón para la mejora del rendimiento se debe al protocolo de flujo de datos tabulares (TDS) de SQL Server, que tiene el principio clave de diseño para transferir datos en formato binario compacto y lo más cerca posible del formato de almacenamiento interno de SQL Server. Empíricamente, esto se observó durante el SSIS 2008: prueba de rendimiento ETL del mundo con Kernrate; el protocolo disminuyó significativamente cuando el tipo de datos se cambió a dinero de decimal. Esto hace que la transferencia de datos sea lo más eficiente posible. Un tipo de datos complejo necesita un análisis adicional y ciclos de CPU para manejar que un tipo de ancho fijo.

Entonces, la respuesta a la pregunta es “depende”. Debe tener más cuidado con ciertas operaciones aritméticas para preservar la precisión, pero puede descubrir que las consideraciones de rendimiento hacen que esto valga la pena.

Acabamos de encontrarnos con un problema muy similar y ahora soy mucho +1 por nunca usar Money, excepto en la presentación de nivel superior. Tenemos varias tablas (de hecho, un comprobante de venta y una factura de venta) cada una de las cuales contiene uno o más campos de dinero por razones históricas, y tenemos que realizar un cálculo proporcional para calcular qué parte del impuesto total a la factura es relevante para cada línea en el voucher de ventas. Nuestro cálculo es

 vat proportion = total invoice vat x (voucher line value / total invoice value) 

Esto da como resultado un cálculo de dinero / dinero del mundo real que causa errores de escala en la parte de división, que luego se multiplica en una proporción de cubeta incorrecta. Cuando estos valores se agregan posteriormente, terminamos con una sum de las proporciones del IVA que no se sumn al valor total de la factura. Si alguno de los valores en los corchetes fuera un decimal (estoy a punto de lanzar uno de ellos como tal), la proporción del IVA sería correcta.

Cuando los corchetes no estaban originalmente, esto solía funcionar, creo que debido a los valores más grandes involucrados, simulaba efectivamente una escala más alta. Agregamos los corchetes porque primero estaba haciendo la multiplicación, que en algunos casos raros volaba la precisión disponible para el cálculo, pero esto ahora ha causado este error mucho más común.

Quiero dar una visión diferente de MONEY vs. NUMERICAL, en gran parte basada en mi propia experiencia y experiencia … Mi punto de vista aquí es MONEY, porque he trabajado con él durante un tiempo considerable y nunca he usado NUMERICAL mucho … .

MONEY Pro:

  • Tipo de datos nativos . Utiliza un tipo de datos nativo ( entero ) igual que un registro de CPU (32 o 64 bits), por lo que el cálculo no necesita una sobrecarga innecesaria, por lo que es más pequeño y más rápido … El DINERO necesita 8 bytes y NUMÉRICO (19, 4 ) necesita 9 bytes (12.5% ​​más grande) …

    El DINERO es más rápido siempre que se use para serlo (como dinero). ¿Qué rápido? Mi prueba SUM simple en 1 millón de datos muestra que MONEY es 275 ms y NUMERIC 517 ms … Eso es casi el doble de rápido … ¿Por qué SUM test? Ver el siguiente punto Pro

  • Mejor para el dinero El DINERO es mejor para almacenar dinero y realizar operaciones, por ejemplo, en contabilidad. Un único informe puede ejecutar millones de adiciones (SUM) y algunas multiplicaciones después de que se realiza la operación SUMA. Para aplicaciones de contabilidad muy grandes, es casi dos veces más rápido , y es extremadamente significativo …
  • Baja precisión del dinero El dinero en la vida real no necesita ser muy preciso. Quiero decir, a muchas personas les puede importar aproximadamente 1 centavo USD, pero ¿qué hay de 0,01 centavos de dólar? De hecho, en mi país, los bancos ya no se preocupan por los centavos (dígito después de la coma decimal); No sé sobre el banco de EE. UU. U otro país …

DINERO Con:

  • Precisión limitada . MONEY solo tiene cuatro dígitos (después de la coma) de precisión, por lo que debe convertirse antes de realizar operaciones como división … Pero, de nuevo, el money no necesita ser tan preciso y debe utilizarse como dinero, no solo un número…

Pero … Grande, pero incluso aquí está su aplicación involucrada con dinero real, pero no la use en muchas operaciones SUM, como en contabilidad. Si usas muchas divisiones y multiplicaciones, entonces no deberías usar MONEY …

No debe usar dinero cuando necesite hacer multiplicaciones / divisiones en el valor. El dinero se almacena de la misma forma en que se almacena un número entero, mientras que el decimal se almacena como un punto decimal y dígitos decimales. Esto significa que el dinero perderá precisión en la mayoría de los casos, mientras que el decimal solo lo hará cuando se vuelva a convertir a su escala original. El dinero es un punto fijo, por lo que su escala no cambia durante los cálculos. Sin embargo, debido a que es un punto fijo cuando se imprime como una cadena decimal (a diferencia de una posición fija en una cadena de base 2), los valores hasta la escala de 4 se representan exactamente. Entonces, para sums y restas, el dinero está bien.

Un decimal se representa en la base 10 internamente y, por lo tanto, la posición del punto decimal también se basa en el número base 10. Lo que hace que su parte fraccionaria represente su valor exactamente, al igual que con el dinero. La diferencia es que los valores intermedios de decimal pueden mantener una precisión de hasta 38 dígitos.

Con un número de coma flotante, el valor se almacena en binario como si fuera un número entero, y la posición del punto decimal (o binario, ejem) es relativa a los bits que representan el número. Debido a que es un punto decimal binario, los números de la base 10 pierden precisión justo después del punto decimal. 1/5, o 0.2, no se pueden representar precisamente de esta manera. Ni el dinero ni el decimal sufren de esta limitación.

Es bastante fácil convertir dinero en decimal, realizar los cálculos y luego almacenar el valor resultante en un campo monetario o variable.

Desde mi Punto de vista, quiero que las cosas que les pasan a los números simplemente sucedan sin tener que pensar demasiado en ellas. Si todos los cálculos van a convertirse a decimal, entonces para mí solo me gustaría usar decimal. Guardaría el campo de dinero para mostrarlo.

En lo que respecta al tamaño, no veo la diferencia suficiente como para cambiar de opinión. El dinero toma 4 – 8 bytes, mientras que el decimal puede ser 5, 9, 13 y 17. Los 9 bytes pueden cubrir todo el rango que los 8 bytes de dinero pueden. Index-wise (comparar y buscar debe ser comparable).

Encontré una razón para usar el decimal sobre el dinero en el tema de precisión.

 DECLARE @dOne DECIMAL(19,4), @dThree DECIMAL(19,4), @mOne MONEY, @mThree MONEY, @fOne FLOAT, @fThree FLOAT SELECT @dOne = 1, @dThree = 3, @mOne = 1, @mThree = 3, @fOne = 1, @fThree = 3 SELECT (@dOne/@dThree)*@dThree AS DecimalResult, (@mOne/@mThree)*@mThree AS MoneyResult, (@fOne/@fThree)*@fThree AS FloatResult 

Simplemente pruébelo y tome su decisión.

Acabo de ver esta entrada en el blog: Dinero vs. Decimal en SQL Server .

Lo que básicamente dice que el dinero tiene un problema de precisión …

 declare @m money declare @d decimal(9,2) set @m = 19.34 set @d = 19.34 select (@m/1000)*1000 select (@d/1000)*1000 

Para el tipo de money , obtendrás 19.30 en lugar de 19.34. No estoy seguro de si existe un escenario de aplicación que divide el dinero en 1000 partes para el cálculo, pero este ejemplo sí expone algunas limitaciones.

Todas las publicaciones anteriores aportan puntos válidos, pero algunas no responden la pregunta con precisión.

La pregunta es: ¿por qué alguien preferiría el dinero cuando ya sabemos que es un tipo de datos menos preciso y puede causar errores si se usa en cálculos complejos?

Usas dinero cuando no haces cálculos complejos y puedes cambiar esta precisión por otras necesidades.

Por ejemplo, cuando no tiene que hacer esos cálculos arriba y necesita guardar 1 byte (el dinero toma 8 bytes y el decimal (19,4) toma 9 bytes).

Otro ejemplo, cuando no tiene que hacer esos cálculos arriba y necesita velocidad para procesar una gran cantidad de datos.

Otro ejemplo, cuando no tiene que hacer esos cálculos arriba, y necesita importar cadenas de texto de moneda válidas. Intente hacer esto con otros tipos numéricos: SELECT CONVERT (MONEY, ‘$ 1,000.68’)