Síntoma
Una expresión como importe / unidades funciona para muchas filas, pero falla o devuelve NULL cuando unidades = 0. No intentes ocultar la situación con un valor arbitrario: primero define qué debe representar matemáticamente y en el negocio.
El comportamiento cambia según el motor
| Motor | Comportamiento relevante |
|---|---|
| PostgreSQL | La división por cero corresponde al error SQLSTATE 22012 (division_by_zero). |
| SQL Server | Con ANSI_WARNINGS ON, una división por cero genera error; la configuración puede alterar ese comportamiento. |
| MySQL 8.4 | En un SELECT, la división por cero devuelve NULL; los modos SQL influyen en advertencias y operaciones de escritura. |
| SQLite | Documenta que la división por cero devuelve NULL. |
Por eso no conviene aprender «SQL siempre falla» ni «SQL siempre devuelve NULL». Es una diferencia de motor y configuración que debes tratar de forma deliberada.
Patrón seguro: NULLIF(denominador, 0)
NULLIF(x, 0) devuelve NULL cuando x vale cero. Dividir por NULL produce NULL en lugar de intentar una división matemática inválida. Así expresas que la razón no puede calcularse para esa fila.
WITH metricas(nombre, importe, unidades) AS (
VALUES ('A', 120.0, 4), ('B', 75.0, 0), ('C', 90.0, 3)
)
SELECT
nombre,
importe / NULLIF(unidades, 0) AS importe_por_unidad
FROM metricas
ORDER BY nombre;| nombre | importe_por_unidad |
|---|---|
| A | 30.0 |
| B | NULL |
| C | 30.0 |
¿Y si necesitas mostrar cero?
Puedes envolver la expresión con COALESCE(..., 0), pero solo si cero es el significado correcto. «No se puede calcular una razón porque no hay unidades» no siempre equivale a «la razón es cero».
COALESCE(importe / NULLIF(unidades, 0), 0)Ese patrón cambia un valor desconocido/no calculable por un cero explícito. Úsalo como decisión de negocio, no como parche técnico automático.
CASE también sirve cuando necesitas distinguir casos
Si un denominador cero necesita una etiqueta, una regla distinta o un cálculo alternativo, CASE comunica mejor la decisión:
CASE
WHEN unidades = 0 THEN NULL
ELSE importe / unidades
END AS importe_por_unidadNo cambies el denominador 0 por 1 solo para evitar el error. Eso fabrica un cociente diferente y puede producir métricas engañosas.
Práctica: tasa de conversión
Calcula una tasa sin dividir por cero
Devuelve la tasa compras / visitas para cada campaña. Cuando visitas sea 0, el resultado debe ser NULL.
NULLIF(visitas, 0).1.0 si tu motor necesita forzar un resultado decimal.Solución razonada
WITH campanas(nombre, compras, visitas) AS (
VALUES ('Email', 12, 100), ('Social', 0, 0), ('SEO', 25, 200)
)
SELECT
nombre,
compras * 1.0 / NULLIF(visitas, 0) AS tasa
FROM campanas
ORDER BY nombre;Social devuelve NULL; Email 0.12 y SEO 0.125. La expresión hace visible que una tasa sin visitas no está definida.
Qué debes recordar
- La división por cero no tiene un comportamiento idéntico en todos los motores.
NULLIF(denominador, 0)evita intentar la división y produce un resultado nulo.COALESCE(..., 0)solo es correcto si cero representa realmente el caso de negocio.CASEes preferible cuando necesitas una política especial para el denominador cero.