🙏 Realmente necesitamos su apoyo. Necesitamos financiamiento para continuar nuestra misión: publicar nuevas lecciones y mejorar la plataforma. Si puede, por favor apoye el proyecto con una donación. Ayude al proyecto ahora →
Código SQL copiado al portapapeles

Lesión 6.2 · Tiempo de lectura: ~8 min

Una subconsulta en WHERE te permite filtrar filas basadas en el resultado intermedio de otra consulta. En esta lección, aprenderás cuándo usar operadores de comparación, IN, NOT IN, EXISTS, NOT EXISTS, ANY y ALL, y cómo elegir la opción más segura para tareas prácticas.

Subconsultas en la cláusula WHERE

En la lección anterior, cubrimos la idea general de las subconsultas. Ahora nos enfocamos en el escenario más común: filtrar en WHERE, cuando la consulta externa depende de valores calculados dinámicamente.

En el trabajo real, esto se utiliza constantemente: desde encontrar clientes sin pagos hasta comparar una fila contra un conjunto de resultados.

Diagrama de subconsultas WHERE con operadores IN, EXISTS, ANY y ALL

Subconsultas escalares y operadores de comparación

Si una subconsulta devuelve exactamente un valor, se llama subconsulta escalar. En ese caso, puedes usar operadores estándar =, <>, >, >=, <, <=.

Escenario: encontrar actores con el mismo nombre de pila que el actor con actor_id = 10.

SELECT
    first_name,
    last_name
FROM
    actor
WHERE
    first_name = (
        SELECT first_name
        FROM actor
        WHERE actor_id = 10
    )
    AND actor_id <> 10;

Nota: si la consulta interna devuelve múltiples filas, esta consulta falla con un error.


Subconsultas de múltiples filas: IN y NOT IN

Cuando una subconsulta devuelve una lista de valores (una columna, muchas filas), usa IN.

Escenario: encontrar películas en la categoría Acción.

SELECT
    f.title
FROM
    film AS f
WHERE
    f.film_id IN (
        SELECT
            fc.film_id
        FROM
            film_category AS fc
        WHERE
            fc.category_id = (
                SELECT
                    c.category_id
                FROM
                    category AS c
                WHERE
                    c.name = 'Acción'
            )
    );

Resultado: obtienes todas las películas vinculadas a la categoría Acción a través de la tabla film_category.

NOT IN realiza el filtrado opuesto, pero recuerda una advertencia importante: si el resultado de la subconsulta contiene NULL, la condición puede producir un resultado inesperadamente vacío. En estos casos, NOT EXISTS es a menudo más seguro.


Comprobaciones de existencia: EXISTS y NOT EXISTS

EXISTS verifica si al menos una fila existe en la subconsulta. La base de datos puede detenerse en la primera coincidencia, por lo que este enfoque es a menudo eficiente en tablas grandes.

EXISTS

Escenario: encontrar clientes que tienen al menos un pago.

SELECT
    c.first_name,
    c.last_name
FROM
    customer AS c
WHERE
    EXISTS (
        SELECT
            1
        FROM
            payment AS p
        WHERE
            p.customer_id = c.customer_id
    );

Nota: con EXISTS, SELECT 1 se usa comúnmente porque solo importa la existencia de la fila, no los valores de las columnas devueltas.

NOT EXISTS

Escenario: encontrar clientes que no han realizado ningún pago.

SELECT
    c.first_name,
    c.last_name
FROM
    customer AS c
WHERE
    NOT EXISTS (
        SELECT
            1
        FROM
            payment AS p
        WHERE
            p.customer_id = c.customer_id
    );

Resultado: solo se devuelven los clientes sin filas coincidentes en payment.


Comparando contra un conjunto: ANY y ALL

  • ANY: la condición es verdadera si es verdadera para al menos un valor de la subconsulta.
  • ALL: la condición es verdadera solo si es verdadera para cada valor de la subconsulta.

Escenario: comparar la longitud de la película con las longitudes de las películas en la categoría Comedia.

SELECT
    f.title,
    f.length
FROM
    film AS f
WHERE
    f.length > ANY (
        SELECT
            f2.length
        FROM
            film AS f2
        INNER JOIN film_category AS fc ON f2.film_id = fc.film_id
        INNER JOIN category AS c ON fc.category_id = c.category_id
        WHERE
            c.name = 'Comedia'
    );

Resultado: una película se incluye si es más larga que al menos una película en Comedia.

SELECT
    f.title,
    f.length
FROM
    film AS f
WHERE
    f.length > ALL (
        SELECT
            f2.length
        FROM
            film AS f2
        INNER JOIN film_category AS fc ON f2.film_id = fc.film_id
        INNER JOIN category AS c ON fc.category_id = c.category_id
        WHERE
            c.name = 'Comedia'
    );

Resultado: una película se incluye solo si es más larga que cada película en Comedia.


Qué observar en consultas reales

  • Para un solo valor, usa una subconsulta escalar con un operador de comparación.
  • Para una lista de valores, usa IN o EXISTS dependiendo de la tarea.
  • Para encontrar relaciones faltantes, prefiere NOT EXISTS, especialmente cuando los valores NULL son posibles.
  • Siempre verifica si una subconsulta puede devolver más filas de las esperadas.

Conclusiones clave de esta lección:

  • WHERE con subconsultas permite un filtrado dinámico sin sustitución manual de valores.
  • IN es conveniente para verificar la pertenencia a una lista de valores.
  • EXISTS y NOT EXISTS son efectivos para probar la presencia y ausencia de filas relacionadas.
  • ANY y ALL te permiten comparar una fila contra un conjunto completo de valores.
  • Elegir el operador correcto hace que las consultas sean más precisas, legibles y confiables.

Preguntas Frecuentes

¿Cuál es mejor para encontrar relaciones faltantes: NOT IN o NOT EXISTS?

En la mayoría de las tareas prácticas, NOT EXISTS es más seguro. Si una subconsulta NOT IN devuelve NULL, el resultado puede volverse inesperado y filtrar demasiadas filas.

¿Por qué la gente suele escribir SELECT 1 en EXISTS en lugar de SELECT *?

Porque EXISTS solo verifica si las filas existen. Los valores de las columnas seleccionadas no se utilizan, por lo que SELECT 1 es una forma estándar y clara.

¿Cuándo debo usar ANY y cuándo debo usar ALL?

Usa ANY cuando la condición debe ser verdadera para al menos un valor de la subconsulta. Usa ALL cuando la condición debe ser verdadera para cada valor en el conjunto.

Preguntas de Entrevista

¿Cuál es la diferencia entre IN y EXISTS en SQL?

IN compara un valor con una lista devuelta por una subconsulta, mientras que EXISTS verifica si hay al menos una fila coincidente. En conjuntos de datos grandes, EXISTS es a menudo más eficiente en patrones correlacionados porque puede detenerse en la primera coincidencia.

¿Cómo explicarías la diferencia entre subconsultas escalares y de múltiples filas?

Una subconsulta escalar devuelve un valor y se usa con operadores como = o >. Una subconsulta de múltiples filas devuelve un conjunto de valores y se usa generalmente con IN, ANY o ALL.

¿Por qué puede fallar una consulta con el operador = y una subconsulta?

El operador = espera un solo valor en el lado derecho. Si la subconsulta devuelve más de una fila, el motor SQL no puede realizar una comparación inequívoca y genera un error.

En la próxima lección, veremos subconsultas correlacionadas y cómo se ejecutan fila por fila en la consulta externa.