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.
Un método de diagnóstico en cuatro pasos
- Describe el síntoma: ¿la sentencia no se ejecuta, devuelve demasiadas filas o cambia más datos de los previstos?
- Reduce el caso: conserva la menor consulta que todavía reproduce el problema.
- Comprueba una hipótesis: revisa orden de cláusulas, multiplicidad de las relaciones o alcance del filtro.
- 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.
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.
Error de sintaxis SQL
Localiza comas, comillas, paréntesis, orden de cláusulas y sintaxis que pertenece a otro motor.
Diagnosticar sintaxis →Aparecen demasiadas filasDuplicados 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 datosUPDATE 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 NULLNULL 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 NULLDesigualdad 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 izquierdaLEFT 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 ambiguaColumna 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 usarColumna ambigua
Distingue columnas con el mismo nombre mediante alias de tabla y nombres de salida claros.
Resolver la referencia →El motor no reconoce una columnaColumna no existe
Comprueba nombre, tabla, alias y alcance antes de cambiar el esquema o reescribir filtros.
Resolver el nombre →La subconsulta produce varios valoresSubconsulta 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 columnasSubconsulta 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 WHEREFunció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()) fallaFunciones 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ónFOREIGN 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 filaColumnas 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 columnaValor 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 datoValor 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 obligatorioNOT 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 reglaCHECK 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 solapanLa 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 encajanORDER 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 ramasEl 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 tiposTipos 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 aliasAlias 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 WHEREFunció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 noLa 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 filasNULL 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 coincidenciaCOUNT(*) 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 NULLDivisió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 decimalDivisión entera trunca decimales
Comprueba los tipos antes de dividir y distingue / de la división entera específica de cada motor.
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 concurrenciaDeadlock / 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
| Síntoma | Primera hipótesis | Qué comprobar |
|---|---|---|
| El motor rechaza la sentencia | Sintaxis o dialecto | Token cercano, delimitadores y orden de cláusulas |
| El JOIN devuelve más filas | Cardinalidad | Cuántas coincidencias tiene cada clave |
| UPDATE/DELETE toca demasiadas filas | Alcance | El mismo WHERE con SELECT y una transacción de prueba |
| La consulta se ejecuta pero el dato es incorrecto | Lógica | Predicado, NULL, agrupación y granularidad del resultado |
| Un LEFT JOIN pierde filas de la izquierda | Filtro posterior al JOIN | Condiciones sobre la tabla derecha en ON frente a WHERE |
| GROUP BY falla o devuelve una columna impredecible | Columna no agrupada | Granularidad y columnas no agregadas del SELECT |
| El motor dice que una columna es ambigua | Resolución de nombres | Prefijos con alias cuando varias tablas comparten el nombre |
| El motor dice que una columna no existe | Resolución de nombres | Esquema real, tabla/alias visible y alcance del identificador |
| Una subconsulta usada como valor devuelve varias filas | Cardinalidad escalar | Ejecutar la subconsulta sola y decidir entre valor único, IN o EXISTS |
| COUNT, SUM o AVG falla dentro de WHERE | Orden lógico de agregación | Separar condiciones de filas (WHERE) y de grupos (HAVING) |
| Una agregación aparece dentro de otra | Dos niveles de resumen en el mismo SELECT | Calcular el agregado interior en una subconsulta o CTE y agregar después |
| FOREIGN KEY impide insertar, actualizar o borrar | Integridad referencial | Clave hija, fila padre y acción ON DELETE/ON UPDATE |
| INSERT tiene distinto número de columnas y valores | Forma de la fila | Lista de columnas, VALUES y columnas omitidas con DEFAULT |
| El texto supera el tamaño de VARCHAR | Longitud del dato | Medir el valor, comprobar el límite real y distinguir caracteres de bytes según el motor |
| UNIQUE rechaza un valor | Duplicado lógico | Buscar la fila que ya contiene la clave única |
| NOT NULL rechaza INSERT o UPDATE | Dato obligatorio ausente | Distinguir NULL explícito, columna omitida y DEFAULT |
| CHECK rechaza una fila | Regla de dominio incumplida | Evaluar la condición con los valores concretos |
| La paginación repite o salta filas | Orden no determinista | Añadir un criterio único al final de ORDER BY |
| UNION falla al combinar consultas | Estructuras con distinto número de columnas | Alinear cantidad y significado de columnas por posición |
| UNION tiene el mismo número de columnas pero falla | Tipos incompatibles por posición | Definir el tipo común y convertir explícitamente solo si conserva la intención |
| WHERE no reconoce un alias de SELECT | Orden lógico / alcance del alias | Repetir la expresión o crear una capa intermedia |
| ROW_NUMBER o RANK falla en WHERE | La ventana se calcula después del filtro | Calcular en una subconsulta o CTE y filtrar fuera |
| La CTE no existe en la siguiente consulta | WITH tiene alcance de una sentencia | Redefinir la CTE o elegir un objeto persistente |
| LEFT JOIN muestra 1 en un grupo sin coincidencias | COUNT(*) cuenta la fila preservada | Contar una columna NOT NULL de la tabla derecha |
| Una división falla o devuelve NULL | Denominador igual a cero | Proteger el denominador con NULLIF o CASE |
| Una división devuelve un entero inesperado | División entre tipos enteros | Tipos del numerador/denominador y reglas del motor antes de aplicar ROUND |
| DISTINCT falla al ordenar por otra columna | Clave de orden ambigua | Qué valor de ORDER BY representa cada fila deduplicada |
| Una fecha de texto no se puede convertir | Formato o calendario inválido | Valor original, formato esperado y reglas del motor |
| Una transacción se revierte por deadlock | Ciclo de bloqueos | Orden de acceso a filas/tablas y qué transacción espera a cuál |
| DROP COLUMN falla aunque la columna existe | Dependencia de esquema | Índices, constraints, vistas, triggers y columnas generadas que todavía la usan |
Comprobación rápida
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?
ON.Respuesta razonada
Empieza por la cardinalidad del JOIN. Si una fila de pedidos coincide con varias filas de detalle, el resultado tendrá una fila por combinación válida. Añadir DISTINCT sin entender esa multiplicidad puede ocultar el síntoma sin resolver la intención.
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.