⏳ ¡Últimos días de octubre! SQLtest.online es gratuito gracias a las donaciones, y aún necesitamos alcanzar la meta de este mes para que el sitio siga funcionando en noviembre. Cada donación cuenta. Apoyar ahora →
Código SQL copiado al portapapeles

Subconsultas en la cláusula WHERE

Lección 6.2 · Tiempo de lectura: ~8 min · Tareas de práctica ↓

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

En la lección anterior vimos la idea general de las subconsultas. Ahora nos centramos en el caso más habitual: el filtrado en WHERE, cuando la consulta externa depende de valores calculados dinámicamente.

En el trabajo real esto se usa constantemente: desde buscar clientes sin pagos hasta comparar una fila con un conjunto de resultados.

Diagrama de subconsultas en WHERE con los 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 los operadores habituales =, <>, >, >=, <, <=.

Escenario: encontrar los actores que tienen el mismo nombre 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 varias filas, la consulta falla con un error.


Subconsultas de varias filas: IN y NOT IN

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

Escenario: encontrar las películas de la categoría Action.

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 = 'Action'
            )
    );

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

NOT IN hace el filtrado contrario, pero ten en cuenta una advertencia importante: si el resultado de la subconsulta contiene NULL, la condición puede dar un resultado vacío inesperado. En esos casos, NOT EXISTS suele ser más seguro.


Comprobar la existencia: EXISTS y NOT EXISTS

EXISTS comprueba si la subconsulta devuelve al menos una fila. La base de datos puede detenerse en la primera coincidencia, por lo que este enfoque suele ser eficiente en tablas grandes.

EXISTS

Escenario: encontrar los 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 se suele escribir SELECT 1, porque solo importa que la fila exista, no los valores de las columnas devueltas.

NOT EXISTS

Escenario: encontrar los clientes que no han hecho 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 que no tienen filas correspondientes en payment.


Comparar con un conjunto: ANY y ALL

  • ANY: la condición es verdadera si se cumple para al menos un valor de la subconsulta.
  • ALL: la condición es verdadera solo si se cumple para todos los valores de la subconsulta.

Escenario: comparar la duración de una película con las duraciones de las películas de la categoría Comedy.

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 = 'Comedy'
    );

Resultado: una película se incluye si dura más que al menos una película de Comedy.

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 = 'Comedy'
    );

Resultado: una película se incluye solo si dura más que todas las películas de Comedy.


Qué vigilar en las 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 según la tarea.
  • Para encontrar relaciones ausentes, prefiere NOT EXISTS, sobre todo si puede haber valores NULL.
  • Comprueba siempre si la subconsulta puede devolver más filas de las previstas.

Puntos clave de esta lección:

  • WHERE con subconsultas permite filtrar de forma dinámica sin sustituir valores a mano.
  • IN es cómodo para comprobar si un valor pertenece a una lista.
  • EXISTS y NOT EXISTS son eficaces para comprobar la presencia o ausencia de filas relacionadas.
  • ANY y ALL permiten comparar una fila con todo un conjunto de valores.
  • Elegir el operador adecuado hace que las consultas sean más precisas, legibles y fiables.

Preguntas frecuentes

¿Qué es mejor para encontrar relaciones ausentes: NOT IN o NOT EXISTS?

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

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

Porque EXISTS solo comprueba si existen filas. Los valores de las columnas seleccionadas no se usan, así que SELECT 1 es una forma estándar y clara.

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

Usa ANY cuando la condición deba cumplirse para al menos un valor de la subconsulta. Usa ALL cuando deba cumplirse para todos los valores del conjunto.

Preguntas de entrevista

¿Qué diferencia hay entre IN y EXISTS en SQL?

IN compara un valor con una lista devuelta por una subconsulta, mientras que EXISTS comprueba si hay al menos una fila que coincida. Con grandes volúmenes de datos, EXISTS suele ser más eficiente en las subconsultas correlacionadas, porque puede detenerse en la primera coincidencia.

¿Cómo explicarías la diferencia entre las subconsultas escalares y las de varias filas?

Una subconsulta escalar devuelve un solo valor y se usa con operadores como = o >. Una subconsulta de varias filas devuelve un conjunto de valores y suele usarse con IN, ANY o ALL.

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

El operador = espera un único valor a la derecha. Si la subconsulta devuelve más de una fila, el motor SQL no puede hacer una comparación sin ambigüedad y devuelve un error.

Intenta resolver las siguientes tareas para reforzar lo que aprendiste en esta lección.

  1. Lista de Subdepartamentos
  2. Empleados con Altos Salarios
  3. Empleados con Sueldos por Encima del Promedio
  4. Pingüinos de pico pequeño
  5. Direcciones en Londres con Subconsulta