DECIMAL

El tipo DECIMAL (también llamado NUMERIC) almacena números con precisión exacta. A diferencia de FLOAT y DOUBLE, que usan representación en punto flotante y pueden introducir errores de redondeo, DECIMAL almacena cada dígito de forma exacta. Es el tipo obligatorio para valores monetarios, financieros o cualquier dato donde la precisión es crítica.

Sintaxis

DECIMAL(precision, escala)

precision es el número total de dígitos (máximo 65). escala es el número de dígitos después del punto decimal (máximo 30, no puede superar la precisión).

DECIMAL(10, 2)   -- Hasta 99,999,999.99 (8 dígitos enteros + 2 decimales)
DECIMAL(5, 3)    -- Hasta 99.999 (2 dígitos enteros + 3 decimales)
DECIMAL(3, 0)    -- Hasta 999 (solo enteros)

Ejemplo básico

CREATE TABLE precios (
    id INT AUTO_INCREMENT PRIMARY KEY,
    producto VARCHAR(100),
    precio DECIMAL(10, 2) NOT NULL,
    impuesto DECIMAL(5, 4) NOT NULL DEFAULT 0.2100
);
 
INSERT INTO precios (producto, precio, impuesto) VALUES
('Laptop', 999.99, 0.2100),
('Mouse', 29.50, 0.2100),
('Cable', 9.99, 0.1000);
 
SELECT producto, precio, impuesto,
       ROUND(precio * impuesto, 2) AS iva,
       ROUND(precio * (1 + impuesto), 2) AS total
FROM precios;
productoprecioimpuestoivatotal
Laptop999.990.2100210.001209.99
Mouse29.500.21006.2035.70
Cable9.990.10001.0010.99

Los cálculos son exactos: no hay errores de redondeo acumulados.

DECIMAL en tienda_mysql

Nuestra base de datos usa DECIMAL(10, 2) para todos los valores monetarios:

-- productos.precio es DECIMAL(10, 2)
SELECT nombre, precio FROM productos ORDER BY precio DESC LIMIT 5;
nombreprecio
ASUS ROG Zephyrus1899.99
Lenovo ThinkPad X11549.00
MacBook Air M31399.00
iPhone 15 Pro1299.99
Samsung Galaxy S24899.99

DECIMAL(10, 2) permite valores hasta 99,999,999.99, más que suficiente para precios. Los salarios de empleados también usan DECIMAL(10, 2):

SELECT nombre, salario FROM empleados ORDER BY salario DESC LIMIT 3;
nombresalario
Ricardo75000.00
Sofía55000.00
Alberto52000.00

Por qué no FLOAT para dinero

La diferencia entre DECIMAL y FLOAT es fundamental para valores monetarios:

CREATE TABLE comparacion (
    valor_decimal DECIMAL(10, 2),
    valor_float FLOAT
);
 
INSERT INTO comparacion VALUES (0.1 + 0.2, 0.1 + 0.2);
 
SELECT
    valor_decimal,
    valor_float,
    valor_decimal = 0.30 AS decimal_exacto,
    valor_float = 0.30 AS float_exacto
FROM comparacion;
valor_decimalvalor_floatdecimal_exactofloat_exacto
0.300.300000011920929010

DECIMAL almacena 0.30 exactamente. FLOAT introduce un error microscópico que hace que la comparación con 0.30 falle. En una aplicación financiera, estos errores se acumulan y causan descuadres.

Precisión y escala

La elección de precisión y escala depende del caso de uso:

-- Precios: 8 dígitos enteros + 2 decimales
precio DECIMAL(10, 2)    -- Hasta 99,999,999.99
 
-- Porcentajes: hasta 100.00
porcentaje DECIMAL(5, 2) -- Hasta 999.99
 
-- Tipo de cambio: muchos decimales
tipo_cambio DECIMAL(12, 6) -- Hasta 999,999.999999
 
-- Coordenadas GPS: alta precisión
latitud DECIMAL(9, 6)    -- Hasta ±999.999999
longitud DECIMAL(9, 6)

Si insertas un valor que excede la precisión, MySQL devuelve un error en modo estricto:

CREATE TABLE test_precision (valor DECIMAL(5, 2));
 
INSERT INTO test_precision VALUES (999.99);  -- OK
INSERT INTO test_precision VALUES (1000.00); -- Error
ERROR 1264 (22003): Out of range value for column 'valor' at row 1

Si el valor tiene más decimales de los permitidos, MySQL los redondea:

INSERT INTO test_precision VALUES (99.999);
SELECT * FROM test_precision;
valor
999.99
100.00

99.999 se redondeó a 100.00 (que cabe en DECIMAL(5, 2)).

Valores por defecto

DECIMAL         -- Equivale a DECIMAL(10, 0): 10 dígitos, sin decimales
DECIMAL(5)      -- Equivale a DECIMAL(5, 0): 5 dígitos, sin decimales
DECIMAL(10, 2)  -- 10 dígitos totales, 2 decimales

Si omites la escala, MySQL asume 0 (solo enteros). Si omites ambos, asume DECIMAL(10, 0).

Almacenamiento

DECIMAL usa un formato empaquetado que almacena 9 dígitos decimales en 4 bytes. El espacio depende de la precisión:

Dígitos    Bytes
1-2        1
3-4        2
5-6        3
7-9        4

DECIMAL(10, 2) necesita 5 bytes: 4 bytes para los 8 dígitos enteros + 1 byte para los 2 decimales. Es más compacto que almacenar el número como texto, pero menos que FLOAT (4 bytes) o DOUBLE (8 bytes).

Operaciones aritméticas

Las operaciones con DECIMAL mantienen la precisión:

SELECT
    CAST(10 AS DECIMAL(10,2)) / 3 AS division,
    CAST(1.00 AS DECIMAL(10,2)) / 7 AS septimos;
divisionseptimos
3.3333330.142857

MySQL extiende la precisión del resultado automáticamente para evitar pérdida de información.

Para cálculos financieros, usa ROUND explícitamente:

SELECT
    precio,
    ROUND(precio * 0.21, 2) AS iva,
    ROUND(precio * 1.21, 2) AS con_iva
FROM productos
WHERE id = 1;
precioivacon_iva
1299.99273.001572.99

Funciones de agregación

Las funciones SUM, AVG sobre columnas DECIMAL producen resultados DECIMAL:

SELECT
    SUM(precio) AS suma_precios,
    AVG(precio) AS precio_medio,
    MIN(precio) AS mas_barato,
    MAX(precio) AS mas_caro
FROM productos;
suma_preciosprecio_mediomas_baratomas_caro
14592.54486.418012.991899.99

NUMERIC y DEC

NUMERIC y DEC son sinónimos de DECIMAL. Las tres formas son idénticas:

columna DECIMAL(10, 2)
columna NUMERIC(10, 2)
columna DEC(10, 2)

DECIMAL es la forma más común y la recomendada.

Limpieza

DROP TABLE IF EXISTS precios;
DROP TABLE IF EXISTS comparacion;
DROP TABLE IF EXISTS test_precision;

En el siguiente artículo veremos FLOAT y DOUBLE, los tipos de punto flotante para valores aproximados donde la velocidad importa más que la precisión exacta.

Escrito por Eduardo Lázaro