Recuperación · diagnóstico por síntomas

Errores SQL: diagnostica el problema antes de cambiar la consulta

Identifica si el bloqueo es de sintaxis, cardinalidad o alcance de una modificación y aplica una comprobación pequeña antes de probar cambios al azar.

Guías de recuperaciónEjemplos comprobadosSin memorizar mensajes de error

Un método de diagnóstico en cuatro pasos

  1. Describe el síntoma: ¿la sentencia no se ejecuta, devuelve demasiadas filas o cambia más datos de los previstos?
  2. Reduce el caso: conserva la menor consulta que todavía reproduce el problema.
  3. Comprueba una hipótesis: revisa orden de cláusulas, multiplicidad de las relaciones o alcance del filtro.
  4. Vuelve a ampliar: añade una pieza cada vez y predice qué debería cambiar.

Estas páginas no sustituyen las lecciones del curso. Están pensadas para cuando ya conoces la idea básica pero una consulta concreta se comporta de forma inesperada.

Elige por síntoma

Veintinueve bloqueos frecuentes con una recuperación concreta

Empieza por el síntoma observable. Evita arreglar una consulta con DISTINCT, filtros nuevos o cambios destructivos sin saber primero qué está fallando.

La consulta no se ejecuta

Error de sintaxis SQL

Localiza comas, comillas, paréntesis, orden de cláusulas y sintaxis que pertenece a otro motor.

Diagnosticar sintaxis →
Aparecen demasiadas filas

Duplicados después de un JOIN

Distingue duplicados reales de relaciones uno-a-muchos y corrige la granularidad sin ocultarla con DISTINCT.

Revisar cardinalidad →
Cambios de datos

UPDATE o DELETE afecta demasiadas filas

Comprueba el filtro con SELECT, ensaya dentro de una transacción y confirma el alcance antes de COMMIT.

Proteger la modificación →
El filtro ignora NULL

NULL no devuelve las filas esperadas

Entiende por qué = NULL y <> NULL no expresan ausencia y cuándo usar IS NULL o IS NOT NULL.

Corregir el filtro →
<> elimina también los NULL

Desigualdad en WHERE pierde valores desconocidos

Decide si una columna nullable debe conservar sus NULL cuando excluyes un valor conocido con <> o !=.

Revisar la desigualdad →
Faltan filas de la izquierda

LEFT JOIN pierde filas

Comprueba si un filtro sobre la tabla derecha en WHERE está eliminando las filas extendidas con NULL.

Revisar ON y WHERE →
La agregación falla o es ambigua

Columna no agrupada en GROUP BY

Define la granularidad y evita columnas cuyo valor no está determinado por el grupo.

Revisar la agrupación →
El motor no sabe qué columna usar

Columna ambigua

Distingue columnas con el mismo nombre mediante alias de tabla y nombres de salida claros.

Resolver la referencia →
El motor no reconoce una columna

Columna no existe

Comprueba nombre, tabla, alias y alcance antes de cambiar el esquema o reescribir filtros.

Resolver el nombre →
La subconsulta produce varios valores

Subconsulta devuelve más de una fila

Decide si la consulta exterior necesita un valor único, una lista con IN o una comprobación con EXISTS.

Revisar cardinalidad →
La subconsulta devuelve demasiadas columnas

Subconsulta devuelve más de una columna

Distingue una subconsulta escalar de un valor de fila y selecciona solo el dato que la expresión exterior necesita.

Revisar la forma →
COUNT o SUM falla dentro de WHERE

Función de agregación en WHERE

Separa filtros de filas y grupos y mueve a HAVING solo las condiciones que dependen del agregado.

Separar WHERE y HAVING →
AVG(SUM()) o SUM(COUNT()) falla

Funciones de agregación anidadas

Separa el resumen interior del exterior con una subconsulta o CTE y comprueba si realmente necesitas dos granularidades.

Separar los niveles →
INSERT o DELETE rompe una relación

FOREIGN KEY falla

Encuentra la clave padre que falta o la fila hija que impide borrar antes de cambiar la restricción.

Revisar la referencia →
El INSERT no puede emparejar la fila

Columnas y valores no coinciden

Cuenta columnas y expresiones de VALUES y usa DEFAULT mediante una lista de destino explícita.

Corregir el INSERT →
El texto no cabe en la columna

Valor demasiado largo para VARCHAR

Compara el valor con el límite real y decide si debes corregir el dato o ampliar la columna sin truncar información a ciegas.

Diagnosticar longitud →
UNIQUE rechaza el dato

Valor duplicado en UNIQUE

Localiza la fila que ya usa la clave y decide si debes actualizarla o corregir el nuevo dato.

Buscar el duplicado →
Falta un valor obligatorio

NOT NULL falla

Distingue un NULL explícito, una columna omitida y una regla de obligatoriedad mal modelada.

Encontrar el valor ausente →
El dato no cumple una regla

CHECK constraint falla

Evalúa la condición con el valor rechazado antes de cambiar una restricción que protege el dominio.

Revisar la condición →
Las páginas cambian o se solapan

La paginación repite o salta filas

Añade un desempate único a ORDER BY y separa la inestabilidad del orden de los cambios en los datos.

Estabilizar el orden →
DISTINCT y ORDER BY no encajan

ORDER BY usa una columna no seleccionada

Define qué clave debe ordenar cada fila deduplicada sin añadir una columna que destruya la unicidad del resultado.

Revisar DISTINCT y orden →
UNION no puede combinar las ramas

El número de columnas no coincide

Alinea la cantidad, el significado y los tipos de las columnas antes de combinar resultados.

Alinear las consultas →
UNION tiene la misma forma, pero falla por tipos

Tipos incompatibles en UNION

Compara cada posición y convierte solo hacia un tipo común que represente el mismo dato.

Revisar los tipos →
WHERE no reconoce el alias

Alias de SELECT fuera de alcance

Repite la expresión o crea una subconsulta/CTE para filtrar el resultado en la etapa correcta.

Corregir el alias →
ROW_NUMBER o RANK falla en WHERE

Función de ventana en WHERE

Calcula la ventana primero y filtra su alias desde una consulta exterior.

Separar cálculo y filtro →
WITH funcionó una vez y luego no

La CTE quedó fuera de alcance

Una CTE vive durante una sentencia; decide si debes redefinirla o usar una vista/tabla.

Entender el alcance →
NOT IN devuelve cero filas

NULL dentro de NOT IN

Detecta por qué un NULL en la lista o subconsulta vuelve desconocida la exclusión y corrígelo con IS NOT NULL o NOT EXISTS.

Corregir la exclusión →
Un LEFT JOIN cuenta 1 aunque no haya coincidencia

COUNT(*) devuelve 1 en vez de 0

Distingue la fila preservada del LEFT JOIN de una coincidencia real y cuenta una columna no nula de la tabla derecha.

Corregir el recuento →
Una fórmula falla o devuelve NULL

División por cero

Protege el denominador con NULLIF o CASE y distingue el comportamiento de PostgreSQL, SQL Server, MySQL y SQLite.

Proteger la división →
Una división pierde la parte decimal

División entera trunca decimales

Comprueba los tipos antes de dividir y distingue / de la división entera específica de cada motor.

Recuperar los decimales →
La conversión temporal rechaza el texto

Fecha no válida al convertir texto

Distingue un formato ambiguo de una fecha imposible y valida los datos antes de CAST, CONVERT o una función temporal.

Revisar la fecha →
La transacción se revierte por concurrencia

Deadlock / interbloqueo

Reconoce el ciclo de bloqueos, ordena el acceso a recursos y reintenta la transacción abortada con seguridad.

Diagnosticar deadlock →

No todos los resultados inesperados son errores de sintaxis

Primer diagnóstico según el síntoma
SíntomaPrimera hipótesisQué comprobar
El motor rechaza la sentenciaSintaxis o dialectoToken cercano, delimitadores y orden de cláusulas
El JOIN devuelve más filasCardinalidadCuántas coincidencias tiene cada clave
UPDATE/DELETE toca demasiadas filasAlcanceEl mismo WHERE con SELECT y una transacción de prueba
La consulta se ejecuta pero el dato es incorrectoLógicaPredicado, NULL, agrupación y granularidad del resultado
Un LEFT JOIN pierde filas de la izquierdaFiltro posterior al JOINCondiciones sobre la tabla derecha en ON frente a WHERE
GROUP BY falla o devuelve una columna impredecibleColumna no agrupadaGranularidad y columnas no agregadas del SELECT
El motor dice que una columna es ambiguaResolución de nombresPrefijos con alias cuando varias tablas comparten el nombre
El motor dice que una columna no existeResolución de nombresEsquema real, tabla/alias visible y alcance del identificador
Una subconsulta usada como valor devuelve varias filasCardinalidad escalarEjecutar la subconsulta sola y decidir entre valor único, IN o EXISTS
COUNT, SUM o AVG falla dentro de WHEREOrden lógico de agregaciónSeparar condiciones de filas (WHERE) y de grupos (HAVING)
Una agregación aparece dentro de otraDos niveles de resumen en el mismo SELECTCalcular el agregado interior en una subconsulta o CTE y agregar después
FOREIGN KEY impide insertar, actualizar o borrarIntegridad referencialClave hija, fila padre y acción ON DELETE/ON UPDATE
INSERT tiene distinto número de columnas y valoresForma de la filaLista de columnas, VALUES y columnas omitidas con DEFAULT
El texto supera el tamaño de VARCHARLongitud del datoMedir el valor, comprobar el límite real y distinguir caracteres de bytes según el motor
UNIQUE rechaza un valorDuplicado lógicoBuscar la fila que ya contiene la clave única
NOT NULL rechaza INSERT o UPDATEDato obligatorio ausenteDistinguir NULL explícito, columna omitida y DEFAULT
CHECK rechaza una filaRegla de dominio incumplidaEvaluar la condición con los valores concretos
La paginación repite o salta filasOrden no deterministaAñadir un criterio único al final de ORDER BY
UNION falla al combinar consultasEstructuras con distinto número de columnasAlinear cantidad y significado de columnas por posición
UNION tiene el mismo número de columnas pero fallaTipos incompatibles por posiciónDefinir el tipo común y convertir explícitamente solo si conserva la intención
WHERE no reconoce un alias de SELECTOrden lógico / alcance del aliasRepetir la expresión o crear una capa intermedia
ROW_NUMBER o RANK falla en WHERELa ventana se calcula después del filtroCalcular en una subconsulta o CTE y filtrar fuera
La CTE no existe en la siguiente consultaWITH tiene alcance de una sentenciaRedefinir la CTE o elegir un objeto persistente
LEFT JOIN muestra 1 en un grupo sin coincidenciasCOUNT(*) cuenta la fila preservadaContar una columna NOT NULL de la tabla derecha
Una división falla o devuelve NULLDenominador igual a ceroProteger el denominador con NULLIF o CASE
Una división devuelve un entero inesperadoDivisión entre tipos enterosTipos del numerador/denominador y reglas del motor antes de aplicar ROUND
DISTINCT falla al ordenar por otra columnaClave de orden ambiguaQué valor de ORDER BY representa cada fila deduplicada
Una fecha de texto no se puede convertirFormato o calendario inválidoValor original, formato esperado y reglas del motor
Una transacción se revierte por deadlockCiclo de bloqueosOrden de acceso a filas/tablas y qué transacción espera a cuál
DROP COLUMN falla aunque la columna existeDependencia de esquemaÍndices, constraints, vistas, triggers y columnas generadas que todavía la usan

Comprobación rápida

Básica · diagnóstico

Clasifica el problema antes de tocar el SQL

Una consulta con JOIN devuelve cinco filas cuando esperabas dos, no muestra ningún mensaje de error y cada pedido aparece varias veces. ¿Qué revisarías primero?

Qué hacer después

  • Si la sentencia no se ejecuta, abre la guía de sintaxis.
  • Si el número de filas crece tras unir tablas, revisa cardinalidad.
  • Si vas a modificar datos, mide primero el alcance con SELECT.
  • Si el problema mezcla varios conceptos, vuelve a las rutas de recuperación.

Fuentes técnicas de referencia