El síntoma: esperabas 2,5 y obtuviste 2
El problema aparece en porcentajes, promedios manuales, tasas o ratios cuando numerador y denominador son enteros. La consulta es sintácticamente válida, pero el tipo de la operación decide si puede existir una parte fraccionaria.
SELECT 5 / 2 AS resultado;| resultado |
|---|
| 2 |
En SQLite ambos literales son enteros, por lo que usa aritmética entera y el cociente se trunca hacia cero. PostgreSQL y SQL Server siguen la misma idea para operandos integrales. No es un problema de ROUND: la fracción ya desapareció antes de cualquier redondeo posterior.
Corrige el tipo antes de dividir
Haz que al menos uno de los operandos participe como valor decimal o aproximado. Para una fórmula sencilla, un literal como 1.0 vuelve visible la intención:
SELECT 1.0 * 5 / 2 AS resultado;| resultado |
|---|
| 2.5 |
Cuando el tipo final importa —por ejemplo, dinero o una métrica que debe conservar una escala concreta— es preferible expresar el contrato con CAST hacia un tipo decimal apropiado para tu motor en vez de depender solo de un literal.
Modelo mental: primero decide qué tipo necesita el cálculo; después divide; al final, si la presentación lo exige, redondea. ROUND(5 / 2, 2) no recupera una fracción que la división entera ya eliminó.
La misma expresión no significa exactamente lo mismo en todos los motores
| Motor | Qué ocurre con enteros | Patrón para conservar decimales |
|---|---|---|
| PostgreSQL 18 | La división de tipos integrales trunca hacia cero: 5 / 2 devuelve 2. | Usa un operando numeric, por ejemplo 5.0 / 2 o un CAST. |
| SQL Server | Si dividendo y divisor son enteros, el resultado es entero y se trunca la parte fraccionaria. | Convierte uno de los operandos a decimal/numeric antes de dividir. |
| SQLite | Usa aritmética entera cuando ambos operandos son enteros y no hay overflow; la división entera trunca hacia cero. | Introduce un valor real, por ejemplo 1.0 * numerador / denominador, o aplica un CAST adecuado. |
| MySQL 8.4 | / no actúa como división entera: con valores exactos conserva escala. El operador DIV sí descarta la parte fraccionaria. | Para cocientes con decimales usa /; evita sustituirlo por DIV si necesitas la fracción. |
Esta diferencia importa al mover una consulta entre motores. Una fórmula que ya devuelve decimales en MySQL puede truncarse al migrarla a PostgreSQL, SQL Server o SQLite si sus columnas son enteras.
Caso frecuente: porcentajes que parecen demasiado pequeños
Si calculas primero una razón entera y luego multiplicas por 100, la pérdida puede ser todavía más visible:
-- Riesgo en motores con división entera
SELECT 2 / 3 * 100 AS porcentaje;
-- Expresa una operación decimal antes de dividir
SELECT 100.0 * 2 / 3 AS porcentaje;En SQLite, la primera expresión devuelve 0 porque 2 / 3 se trunca antes de multiplicar. La segunda conserva la fracción y produce aproximadamente 66,67 si la redondeas a dos decimales.
Método de diagnóstico en cinco pasos
- Reduce la fórmula al numerador y denominador que producen el resultado inesperado.
- Comprueba el tipo real de ambas expresiones, no solo cómo se ven sus valores.
- Ejecuta un caso mínimo como
5 / 2en el mismo motor y entorno. - Promueve uno de los operandos al tipo numérico que necesita la métrica antes de dividir.
- Aplica
ROUNDsolo al final si necesitas limitar la presentación, no para reparar una división entera.
Práctica correctiva
Recupera los decimales de una tasa
Tienes tres métricas con cantidades enteras. Devuelve nombre y un porcentaje redondeado a dos decimales sin perder la fracción durante la división.
Criterio de éxito: A = 25.0, B = 66.67 y C = 75.0.
VALUES.completadas / total con dos enteros.100.0 antes de dividir y redondea al final.Solución razonada
WITH metricas(nombre, completadas, total) AS (
VALUES
('A', 1, 4),
('B', 2, 3),
('C', 3, 4)
)
SELECT nombre,
ROUND(100.0 * completadas / total, 2) AS porcentaje
FROM metricas
ORDER BY nombre;100.0 hace que la expresión conserve una parte decimal antes de la división. ROUND actúa después y limita la presentación a dos decimales; no es quien evita el truncado.
Qué debes recordar
- Una consulta puede ejecutarse correctamente y aun así perder decimales por los tipos de sus operandos.
- PostgreSQL, SQL Server y SQLite truncan la división entre enteros hacia cero.
- MySQL 8.4 usa
/para división con escala yDIVpara división entera. - Promueve el tipo antes de dividir; redondear después no recupera una fracción perdida.
- En cálculos importantes, usa un tipo decimal explícito que refleje la precisión que necesita el dominio.
Conceptos relacionados
Fuentes técnicas
El comportamiento de la división se contrastó con documentación primaria de cada motor: