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;| producto | precio | impuesto | iva | total |
|---|---|---|---|---|
| Laptop | 999.99 | 0.2100 | 210.00 | 1209.99 |
| Mouse | 29.50 | 0.2100 | 6.20 | 35.70 |
| Cable | 9.99 | 0.1000 | 1.00 | 10.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;| nombre | precio |
|---|---|
| ASUS ROG Zephyrus | 1899.99 |
| Lenovo ThinkPad X1 | 1549.00 |
| MacBook Air M3 | 1399.00 |
| iPhone 15 Pro | 1299.99 |
| Samsung Galaxy S24 | 899.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;| nombre | salario |
|---|---|
| Ricardo | 75000.00 |
| Sofía | 55000.00 |
| Alberto | 52000.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_decimal | valor_float | decimal_exacto | float_exacto |
|---|---|---|---|
| 0.30 | 0.3000000119209290 | 1 | 0 |
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); -- ErrorERROR 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 decimalesSi 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;| division | septimos |
|---|---|
| 3.333333 | 0.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;| precio | iva | con_iva |
|---|---|---|
| 1299.99 | 273.00 | 1572.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_precios | precio_medio | mas_barato | mas_caro |
|---|---|---|---|
| 14592.54 | 486.4180 | 12.99 | 1899.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
