Error SQL · cardinalidad de subconsultas

Subconsulta devuelve más de una fila: decide si esperabas un valor o un conjunto

Una subconsulta escalar debe representar un único valor en motores como PostgreSQL y SQL Server. Si devuelve varias filas, corrige primero la intención: valor único, conjunto o existencia.

Lectura: 14–18 minEjemplo reproduciblePráctica con pistas

El síntoma: usas una subconsulta como si fuera un único valor

Una expresión como precio = (SELECT ...) obliga a preguntarte cuántas filas puede producir la consulta interior. En PostgreSQL, una subconsulta escalar debe devolver exactamente una fila y una columna; si devuelve varias filas, el motor rechaza la expresión. SQL Server expone el mismo problema con el error 512 cuando una subconsulta de ese tipo produce más de un valor.

El diagnóstico importante no es “cómo silenciar el mensaje”, sino qué cardinalidad necesita realmente la consulta exterior. Si esperabas una lista, la solución suele ser expresar una operación de conjunto. Si esperabas un único valor, la consulta interior debe demostrar por qué solo puede devolver uno.

Ejemplo reproducible: dos ciudades donde la consulta esperaba una

SQL problemático
WITH clientes(id, ciudad) AS (
  VALUES (1, 'Madrid'),
         (2, 'Sevilla'),
         (3, 'Madrid')
)
SELECT id, ciudad
FROM clientes
WHERE ciudad = (
  SELECT ciudad
  FROM clientes
  WHERE id IN (1, 2)
);

La subconsulta interior produce dos filas: Madrid y Sevilla. El operador = necesita comparar con un solo valor. En PostgreSQL y SQL Server esa forma provoca un error de cardinalidad.

Corrección 1: usa IN cuando la intención es “cualquiera de estos valores”

SQL corregido con conjunto
WITH clientes(id, ciudad) AS (
  VALUES (1, 'Madrid'),
         (2, 'Sevilla'),
         (3, 'Madrid')
)
SELECT id, ciudad
FROM clientes
WHERE ciudad IN (
  SELECT ciudad
  FROM clientes
  WHERE id IN (1, 2)
)
ORDER BY id;
Resultado cuando la intención es pertenecer al conjunto de ciudades
idciudad
1Madrid
2Sevilla
3Madrid

Corrección 2: demuestra la unicidad si de verdad necesitas un valor

Si la regla de negocio dice que la consulta interior identifica una sola fila, exprésala mediante una clave o condición que garantice esa unicidad. Por ejemplo, WHERE id = 1 puede producir un único registro cuando id es una clave única.

No uses LIMIT 1 como parche automático. Elegir una fila arbitraria oculta que la consulta original no definía cuál de las varias filas era la correcta. Solo limita a una fila cuando exista un criterio explícito y, si el orden importa, un ORDER BY que lo haga determinista.

Diferencia importante: SQLite no diagnostica este caso igual

SQLite define el valor de una subconsulta escalar como la primera fila devuelta y usa NULL cuando no hay filas. Eso significa que una consulta que falla en PostgreSQL o SQL Server puede ejecutarse en SQLite y seleccionar silenciosamente una fila. Por portabilidad, no dependas de ese comportamiento: documenta si esperas exactamente una fila o un conjunto.

Método de diagnóstico

  1. Ejecuta la subconsulta sola y cuenta sus filas.
  2. Identifica el contexto exterior: = y una expresión escalar esperan un valor; IN y EXISTS modelan conjuntos o existencia.
  3. Comprueba la unicidad: una clave única es evidencia; “normalmente sale una fila” no lo es.
  4. Predice el caso de cero filas y decide si debe producir NULL, falso, ninguna coincidencia u otro comportamiento.

Error frecuente: cambiar = por IN sin revisar la intención

El error desaparece, pero la pregunta puede cambiar

IN es correcto cuando quieres comparar contra un conjunto. Si la aplicación esperaba una única configuración, tarifa o responsable, varias filas pueden indicar un problema de datos o una condición incompleta. Corrige la cardinalidad, no solo la sintaxis.

Práctica correctiva

Intermedia · subconsultas

Elige entre valor único e IN

Quieres listar clientes que viven en cualquiera de las ciudades de los clientes 1 y 2. ¿Qué operador usarías y por qué?

Qué debes recordar

  • Una subconsulta escalar representa un valor, no una lista.
  • Ejecuta primero la consulta interior y comprueba su cardinalidad.
  • Usa IN o EXISTS cuando la intención sea trabajar con un conjunto.
  • No uses LIMIT 1 para esconder una condición que debería ser única.
  • SQLite y otros motores pueden tratar este caso de forma diferente, así que explicita la intención.

Conceptos relacionados

Fuentes técnicas consultadas