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.
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:
1SELECT city.Name2FROM city INNER JOIN country3ON city.CountryCode = country.Code4WHERE 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:
1SELECT city.Name2FROM city3WHERE city.CountryCode = (4 SELECT country.CountryCode5 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:
1SELECT city.Name2FROM city3WHERE 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:
1SELECT city.Name2FROM city3WHERE city.CountryCode = ( /* esta comparación falla */4 SELECT country.Code5 FROM country6 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
.