Saltearse al contenido

Subconsultas

Un tipo de consulta que no vimos en la materia anterior es la subconsulta (subquery). Esta consiste en ejecutar una sentencia SELECT, llamada subconsulta o consulta interna, dentro de otra sentencia SELECT, INSERT, UPDATE o DELETE, llamada consulta o sentencia externa.

Esta subconsulta puede usarse para obtener un valor en particular (un escalar), una columna, un registro (fila) o todo un result-set. En todos los casos, el fin es usar el resultado en la consulta externa.

En su forma más simple, una subconsulta devuelve un valor único, por lo tanto, puede ser usada casi en cualquier parte de una consulta, como operando o columna resultante.

Figura 1.1

Por ejemplo, aquí se usa la subconsulta como un escalar (ya que la función SUM() devuelve un solo valor) para comparar con el valor de la columna c1 de t1 en el WHERE de la sentencia externa.

Observar que el nombre c1 se usa en ambas consultas, pero en cada una pertenece a tablas distintas (t1 y t2 respectivamente). Cada consulta o subconsulta tiene su propio ámbito, aunque veremos que es posible referenciar nombres definidos fuera de él.

Una subconsulta puede escribirse en la expresión de selección de una sentencia SELECT, en una cláusula WHERE o en una cláusula FROM.

En cualquiera de los casos, una subconsulta debe escribirse siempre entre paréntesis, para evitar ambigüedades con la sentencia externa.

Usando subconsultas en la cláusula WHERE

Es posible ejecutar una subconsulta en la cláusula WHERE de otra consulta, tal como vimos en el primer ejemplo. En este caso, la subconsulta deberá devolver uno o más valores para ser comparados usando los operadores usuales (>, <, =, LIKE, etc.).

Este es uno de sus usos más simples y comunes de las subconsultas y, casi siempre, se puede conseguir el mismo resultado realizando un JOIN.

Veamos un ejercicio del uso de JOIN en la base de datos de prueba World, de un Trabajo Práctico de la materia anterior.

”Obtener una lista de los nombres de todas las ciudades del país con nombre ‘Cameroon’“.

La resolución usando JOIN es la siguiente:

1
SELECT city.Name
2
FROM city INNER JOIN country
3
ON city.CountryCode = country.Code
4
WHERE country.Name = "Cameroon";

Esto se debía a que, la única forma de usar el nombre “Cameroon” en una misma consulta era realizar un JOIN con la tabla country.

Ahora veamos cómo podemos resolverlo con una subconsulta:

1
SELECT city.Name
2
FROM city
3
WHERE city.CountryCode = (
4
SELECT country.CountryCode
5
WHERE country.Name = "Cameroon"
6
);

Podemos ver que la subconsulta (escrita entre paréntesis) obtiene el CountryCode del país con el nombre igual a “Cameroon”. Ya que solo existe un país con ese nombre exacto, la sentencia devuelve solo un valor, el CountryCode “CMR”. Es por esto que podemos usar el operador =.

Si reemplazáramos ese valor en lugar de la subconsulta, la consulta externa quedaría de la siguiente forma:

1
SELECT city.Name
2
FROM city
3
WHERE city.CountryCode = "CMR";

Por lo tanto, solo se devolverán las ciudades del país ‘Cameroon’, como se pedía en la consigna.

Cabe aclarar que si utilizamos una subconsulta que devuelva más de un valor no podremos utilizar un operador que funcione con escalares (como =).

Veamos la misma consulta, pero con una subconsulta que devuelve más de un valor. Por ejemplo:

1
SELECT city.Name
2
FROM city
3
WHERE city.CountryCode = ( /* esta comparación falla */
4
SELECT country.Code
5
FROM country
6
WHERE country.Name LIKE "%on"
7
);

En este caso, la subconsulta devuelve el CountryCode de “Cameroon” y de otros 5 países (cuyos nombres terminan en “on”), por lo tanto, la consulta externa fallará, ya que no puede igualar un city.CountryCode con varios valores a la vez usando =. En este caso debemos utilizar los operadores IN, ANY o ALL.

Bibliografía

  1. MySQL Docs - Subqueries
  2. MySQL Docs - Scalar subqueries