Está en la página 1de 17

Tema 5.

Las subconsultas (I)

Definiciones

Una subconsulta es una sentencia SELECT que aparece dentro de otra


sentencia SELECT que llamaremos consulta principal.

Se puede encontrar en la lista de seleccin, en la clusula WHERE o en la clusula


HAVING de la consulta principal.

Una subconsulta tiene la misma sintaxis que una sentencia SELECT normal exceptuando
que aparece encerrada entre parntesis, no puede contener la clusula ORDER BY, ni
puede ser la UNION de varias sentencias SELECT, adems tiene algunas restricciones en
cuanto a nmero de columnas segn el lugar donde aparece en la consulta principal. Estas
restricciones las iremos describiendo en cada caso.

Cuando se ejecuta una consulta que contiene una subconsulta, la subconsulta se


ejecuta por cada fila de la consulta principal.

Se aconseja no utilizar campos calculados en las subconsultas, ralentizan la consulta.

Las consultas que utilizan subconsultas suelen ser ms fciles de interpretar por el
usuario.

Referencias externas

A menudo, es necesario, dentro del cuerpo de una subconsulta, hacer referencia al valor
de una columna en la fila actual de la consulta principal, ese nombre de columna se
denomina referencia externa.
Una referencia externa es un nombre de columna que estando en la subconsulta, no se
refiere a ninguna columna de las tablas designadas en la FROM de la subconsulta sino a
una columna de las tablas designadas en la FROM de la consulta principal. Como la
subconsulta se ejecuta por cada fila de la consulta principal, el valor de la referencia externa
ir cambiando.

Ejemplo:

SELECT numemp, nombre, (SELECT MIN(fechapedido) FROM pedidos WHERE rep =


numemp)
FROM empleados;

En este ejemplo la consulta principal es SELECT... FROM empleados.


La subconsulta es ( SELECT MIN(fechapedido) FROM pedidos WHERE rep = numemp
).
En esta subconsulta tenemos una referencia externa ( numemp ) es un campo de la tabla
empleados (origen de la consulta principal).

Qu pasa cuando se ejecuta la consulta principal?

- se coge el primer empleado y se calcula la subconsulta sustituyendo numemp por el valor


que tiene en el primer empleado. La subconsulta obtiene la fecha ms antigua en los
pedidos del rep = 101,
- se coge el segundo empleado y se calcula la subconsulta con numemp = 102 (numemp
del segundo empleado)... y as sucesivamente hasta llegar al ltimo empleado.
Al final obtenemos una lista con el nmero, nombre y fecha del primer pedido de cada
empleado.

Si quitamos la clusula WHERE de la subconsulta obtenemos la fecha del primer pedido


de todos los pedidos no del empleado correspondiente.

Anidar subconsultas

Las subconsultas pueden anidarse de forma que una subconsulta aparezca en la


clusula WHERE (por ejemplo) de otra subconsulta que a su vez forma parte de otra
consulta principal. En la prctica, una consulta consume mucho ms tiempo y memoria
cuando se incrementa el nmero de niveles de anidamiento. La consulta resulta tambin
ms difcil de leer , comprender y mantener cuando contiene ms de uno o dos niveles de
subconsultas.

Ejemplo:

SELECT numemp, nombre


FROM empleados
WHERE numemp = (SELECT rep FROM pedidos WHERE clie = (SELECT numclie
FROM clientes WHERE nombre = 'Julia Antequera'))

En este ejemplo, por cada linea de pedido se calcula la subconsulta de clientes, y esto
se repite por cada empleado, en el caso de tener 10 filas de empleados y 200 filas de
pedidos (tablas realmente pequeas), la subconsulta ms interna se ejecutara 2000 veces
(10 x 200).

Subconsulta en la lista de seleccin

Cuando la subconsulta aparece en la lista de seleccin de la consulta principal, en este


caso la subconsulta, no puede devolver varias filas ni varias columnas, de lo contrario
se da un mensaje de error.

Muchos SQLs no permiten que una subconsulta aparezca en la lista de seleccin de la


consulta principal pero eso no es ningn problema ya que normalmente se puede obtener
lo mismo utilizando como origen de datos las dos tablas. El ejemplo anterior se puede
obtener de la siguiente forma:

SELECT numemp, nombre, MIN(fechapedido)


FROM empleados LEFT JOIN pedidos ON empleados.numemp = pedidos.rep
GROUP BY numemp, nombre

En la clusula FROM

En la clusula FROM se puede encontrar una sentencia SELECT encerrada entre


parntesis pero ms que subconsulta sera una consulta ya que no se ejecuta para cada
fila de la tabla origen sino que se ejecuta una sola vez al principio, su resultado se combina
con las filas de la otra tabla para formar las filas origen de la SELECT primera y no admite
referencias externas.

En la clusula FROM vimos que se poda poner un nombre de tabla o un nombre de


consulta, pues en vez de poner un nombre de consulta se puede poner directamente la
sentencia SELECT correspondiente a esa consulta encerrada entre parntesis.
Subconsulta en las clusulas WHERE y
HAVING

Se suele utilizar subconsultas en las clusulas WHERE o HAVING cuando los datos que
queremos visualizar estn en una tabla pero para seleccionar las filas de esa tabla
necesitamos un dato que est en otra tabla.

Ejemplo:

SELECT numemp, nombre


FROM empleados
WHERE contrato = (SELECT MIN(fechapedido) FROM pedidos)

En este ejemplo listamos el nmero y nombre de los empleados cuya fecha de contrato
sea igual a la primera fecha de todos los pedidos de la empresa.

En una clusula WHERE / HAVING tenemos siempre una condicin y la subconsulta


acta de operando dentro de esa condicin.
En el ejemplo anterior se compara contrato con el resultado de la subconsulta. Hasta ahora
las condiciones estudiadas tenan como operandos valores simples (el valor contenido en
una columna de una fila de la tabla, el resultado de una operacin aritmtica...) ahora la
subconsulta puede devolver una columna entera por lo que es necesario definir otro tipo
de condiciones especiales para cuando se utilizan con subconsultas.

Estas nuevas condiciones se describen en la pgina siguiente...

Condiciones de seleccin con subconsultas

Las condiciones de seleccin son las condiciones que pueden aparecer en la


clusula WHERE o HAVING. La mayora se han visto en el tema 2 pero ahora incluiremos
las condiciones que utilizan una subconsulta como operando.

En SQL tenemos cuatro nuevas condiciones:

el test de comparacin con subconsulta


el test de comparacin cuantificada
el test de pertenencia a un conjunto
el test de existencia

En todos los tests estudiados a continuacin expresion puede ser cualquier nombre de
columna de la consulta principal o una expresin vlida como ya vimos en el tema 2.

El test de comparacin con subconsulta.

Es el equivalente al test de comparacin simple. Se utiliza para comparar un valor de


la fila que se est examinado con un nico valor producido por la subconsulta. La
subconsulta debe devolver una nica columna, sino se produce un error.
Si la subconsulta no produce ninguna fila o devuelve el valor nulo, el test devuelve el valor
nulo, si la subconsulta produce varias filas, SQL devuelve una condicin de error.

La sintaxis es la siguiente:
SELECT oficina, ciudad Lista las oficinas cuyo objetivo sea superior a la
FROM oficinas suma de las ventas de sus empleados.
WHERE objetivo > (SELECT En este caso la subconsulta devuelve una nica
SUM(ventas) FROM empleados columna y una nica fila (es un consulta de
WHERE empleados.oficina = resumen sin GROUP BY)
oficinas.oficina)

El test de comparacin cuantificada.

Este test es una extensin del test de comparacin y del test de conjunto. Compara el
valor de la expresin con cada uno de los valores producidos por la subconsulta. La
subconsulta debe devolver una nica columna sino se produce un error.
Tenemos el test ANY (algn, alguno en ingls) y el test ALL (todos en ingls).

La sintaxis es la siguiente:

El test ANY.

La subconsulta debe devolver una nica columna sino se produce un error.


Se evala la comparacin con cada valor devuelto por la subconsulta.
Si alguna de las comparaciones individuales produce el resultado verdadero, el test
ANY devuelve el resultado verdadero.
Si la subconsulta no devuelve ningn valor, el test ANY devuelve falso.
Si el test de comparacin es falso para todos los valores de la
columna, ANY devuelve falso.
Si el test de comparacin no es verdadero para ningn valor de la columna, y es nulo para
al menos alguno de los valores, ANY devuelve nulo.

SELECT oficina, ciudad En este caso la subconsulta devuelve una nica


FROM oficinas columna con las sumas de las cuotas de los
WHERE objetivo > ANY (SELECT empleados de cada oficina.
SUM(cuota) FROM empleados Lista las oficinas cuyo objetivo sea superior a
GROUP BY oficina) alguna de las sumas obtenidas.

El test ALL.

La subconsulta debe devolver una nica columna sino se produce un error.


Se evala la comparacin con cada valor devuelto por la subconsulta.
Si todas las comparaciones individuales, producen un resultado verdadero, el test
devuelve el valor verdadero.
Si la subconsulta no devuelve ningn valor el test ALL devuelve el valor verdadero. (Ojo
con esto!)
Si el test de comparacin es falso para algn valor de la columna, el resultado es falso.
Si el test de comparacin no es falso para ningn valor de la columna, pero es nulo para
alguno de esos valores, el test ALL devuelve valor nulo (Ojo con esto!).

SELECT oficina, ciudad En este caso se listan las oficinas cuyo objetivo
FROM oficinas sea superior a todas las sumas.
WHERE objetivo > ALL (SELECT
SUM(cuota) FROM empleados
GROUP BY oficina)

Test de pertenencia a conjunto (IN).

Examina si el valor de la expresin es uno de los valores incluidos en la lista de


valores producida por la subconsulta.
La subconsulta debe generar una nica columna y las filas que sean.
Si la subconsulta no produce ninguna fila, el test da falso.
Tiene la siguiente sintaxis:

SELECT numemp, nombre, oficina Con la subconsulta se obtiene la lista de los


FROM empleados nmeros de oficina del este y la consulta
WHERE oficina IN (SELECT oficina principal obtiene los empleados cuyo nmero de
FROM oficinas WHERE region = oficina sea uno de los nmeros de oficina
'este') del este.
Por lo tanto lista los empleados de las oficinas
del este.

OJO con NOT IN.


Hay que tener especial cuidado con los valores nulos cuando utilizamos el operador NOT
IN porque el resultado obtenido no siempre ser el deseado. Cuando la subconsulta
devuelve algn nulo el resultado es falso o nulo pero nunca verdadero.

SELECT oficina, ciudad Obtenemos las oficinas que tienen algn


FROM oficinas empleado.
WHERE oficina IN (SELECT oficina
FROM empleados)

SELECT oficina, ciudad Al contrario de lo que podramos pensar esta


FROM oficinas consulta NO devuelve las oficinas que no tienen
WHERE oficina NOT IN (SELECT ningn empleado porque la subconsulta
oficina FROM empleados) devuelve algn NULL ( por los empleados que
no estn asociados a ninguna oficina).

SELECT oficina, ciudad As s.


FROM oficinas
WHERE oficina NOT IN (SELECT
oficina FROM empleados WHERE
oficina IS NOT NULL)

El test de existencia EXISTS.

Examina si la subconsulta produce alguna fila de resultados.


Si la subconsulta contiene filas, el test adopta el valor verdadero, si la subconsulta no
contiene ninguna fila, el test toma el valor falso, nunca puede tomar el valor nulo.
Con este test la subconsulta puede tener varias columnas, no importa ya que el test se
fija no en los valores devueltos sino en si hay o no fila en la tabla resultado de la subconsulta.
Cuando se utiliza el test de existencia en la mayora de los casos habr que utilizar una
referencia externa. Si no se utiliza una referencia externa la subconsulta devuelta siempre
ser la misma para todas las filas de la consulta principal y en este caso se seleccionan
todas las filas de la consulta principal (si la subconsulta genera filas) o ninguna (si la
subconsulta no devuelve ninguna fila)

La sintaxis es la siguiente:

Este ejemplo obtiene lo mismo que el ejemplo del


SELECT numemp, nombre, test IN.
oficina Observa que delante de EXISTS no va ningn
FROM empleados nombre de columna.
WHERE EXISTS (SELECT * FROM En la subconsulta se pueden poner las columnas
oficinas WHERE region = 'este' que queramos en la lista de seleccin (hemos
AND empleados.oficina = utilizado el *).
oficinas.oficina) Hemos aadido una condicin adicional
al WHERE, la de la referencia externa para que
la oficina que se compare sea la oficina del
empleado.

NOTA. Cuando se trabaja con tablas muy voluminosas el test EXISTS suele dar mejor
rendimiento que el test IN.

Resumen del tema

Una subconsulta es una sentencia SELECT que aparece en la lista de seleccin, o en


las clusulas WHERE o HAVING de otra sentencia SELECT.

La subconsulta se ejecuta por cada fila de la consulta principal.

Dentro de una consulta se puede utilizar una columna del origen de la consulta
principal, una referencia externa.

Aunque se puedan anidar subconsultas no es aconsejado ms de un nivel de


anidamiento.

La subconsulta sufre una serie de restricciones segn el lugar donde se encuentre.

Las condiciones asociadas a las subconsultas son las siguientes:


el test de comparacin con subconsulta

el test ANY

el test ALL

el test IN

el test EXISTS

Los ejercicios que te proponemos a continuacin se pueden resolver de varias maneras,


intenta resolverlos utilizando subconsultas ya que de eso trata el tema, adems un mismo
ejercicio lo puedes intentar resolver de diferentes maneras utilizandos distintos tipos de
condiciones, as un ejercicio se puede convertir en dos o tres ejercicios.

1 Listar los nombres de los clientes que tienen asignado el representante Alvaro Jaumes
(suponiendo que no pueden haber representantes con el mismo nombre).

2 Listar los vendedores (numemp, nombre, y n de oficina) que trabajan en oficinas


"buenas" (las que tienen ventas superiores a su objetivo).

3 Listar los vendedores que no trabajan en oficinas dirigidas por el empleado 108.

4 Listar los productos (idfab, idproducto y descripcin) para los cuales no se ha recibido
ningn pedido de 25000 o ms.

5 Listar los clientes asignados a Ana Bustamante que no han remitido un pedido superior
a 3000 pts.

6 Listar las oficinas en donde haya un vendedor cuyas ventas representen ms del 55%
del objetivo de su oficina.

7 Listar las oficinas en donde todos los vendedores tienen ventas que superan al 50%
del objetivo de la oficina.

8 Listar las oficinas que tengan un objetivo mayor que la suma de las cuotas de sus
vendedores.
Ejercicio 1

SELECT nombre Hemos supuesto que no pueden haber dos


FROM clientes empleados con el mismo nombre, de lo
WHERE repclie = (SELECT contrario habra que aadir ANY antes de la
numemp FROM empleados WHERE subconsulta.
nombre = 'Alvaro Jaumes' );

Ejercicio 2

Solucin 1 Con esta solucin buscamos que la oficina del


SELECT numemp, nombre, oficina empleado est en la lista de oficinas que tienen
FROM empleados ventas superiores a su objetivo.
WHERE oficina IN ( SELECT oficina
FROM oficinas WHERE ventas >
objetivo );

Solucin 2 Con esta solucin buscamos que exista una


SELECT numemp, nombre, oficina oficina igual al del empleado y que tenga
FROM empleados ventas superiores a su objetivo. El resultado
WHERE EXISTS ( SELECT * FROM ser el mismo que con la solucin 1.
oficinas WHERE empleados.oficina
= oficinas.oficina AND ventas >
objetivo );

Solucin 3 Con esta otra comparamos la oficina del


SELECT numemp, nombre, oficina empleado con cada una de las oficinas que
FROM empleados tengan ventas superiores a su objetivo, si la
WHERE oficina = ANY ( SELECT oficina del empleado es igual a alguna de esas
oficina FROM oficinas WHERE oficinas aparece el empleado en el resultado.
ventas > objetivo ); El resultado ser el mismo que con la solucin
1.

Ejercicio 3

Solucin 1 Obtenemos los empleados tales que no exista


SELECT numemp, nombre, oficina una oficina igual a la suya que adems est
FROM empleados dirigida por el empleado 108, con esta solucin
WHERE NOT EXISTS ( SELECT * s aparecen los empleados que no tienen
FROM oficinas WHERE oficina.
empleados.oficina =
oficinas.oficina AND dir = 108);

SELECT numemp, nombre, oficina Con la subconsulta obtenemos la lista de las


FROM empleados oficinas dirigidas por el empleado 108. Al final
WHERE oficina NOT IN ( SELECT se obtienen los empleados cuya oficina no est
oficina FROM oficinas WHERE dir = en esa lista, es decir salen los empleados
108); asignados a una oficina no dirigida por el 108.
Pero no salen los empleados que no tienen
oficina asignada ya que su campo oficina es
nulo por lo que el resultado de la comparacin
es nulo, no es verdadero y no se seleccionan.
El problema se puede arreglar indicando que
tambin se tienen que seleccionar los
empleados con oficina nula:

Solucin 2 Con la subconsulta obtenemos la lista de las


SELECT numemp, nombre, oficina oficinas dirigidas por el empleado 108. Al final
FROM empleados se obtienen los empleados cuya oficina no est
WHERE ( oficina NOT IN ( SELECT en esa lista. Pero no salen los empleados que
oficina FROM oficinas WHERE dir = no tienen oficina asignada ya que su campo
108) ) OR ( oficina IS NULL); oficina es nulo por lo que el resultado de la
comparacin es nulo, no es verdadero y no se
seleccionan.

SELECT numemp, nombre, oficina Con esta solucin tenemos el mismo problema
FROM empleados que con NOT IN , cuando la oficina del
WHERE oficina <> ALL ( SELECT empleado es nula todos los resultados de las
oficina FROM oficinas WHERE dir = comparaciones individuales son nulos por los
108); que el test ALL da nulo y no se seleccionan los
empleados con oficina nula.

Ejercicio 4

SELECT idfab, idproducto, En este caso es ms cmodo utilizar NOT


descripcion EXISTS ya que hay que preguntar por
FROM productos el idfab e idproducto a la vez.
WHERE NOT EXISTS (SELECT *
FROM pedidos WHERE fab = idfab
AND producto = idproducto AND
importe >= 25000);

Ejercicio 5

SELECT numclie, nombre Como utilizamos NOT IN debemos


FROM clientes asegurarnos de que la subconsulta no devuelva
WHERE repclie IN ( SELECT nulos. En este caso clie es un campo de
numemp FROM empleados WHERE pedidos que admite nulos por lo que tenemos
nombre = 'Ana Bustamante' ) que aadir en el WHERE de la subconsulta
AND numclie NOT IN ( SELECT clie AND clie IS NOT NULL.
FROM pedidos WHERE importe >
3000 AND clie IS NOT NULL);

Ejercicio 6

SELECT * En una subconsulta todos los campos no


FROM oficinas cualificados se presuponen de la tabla origen
WHERE EXISTS ( SELECT * FROM de la subconsulta y slo si no existe ninguna
empleados WHERE columna con ese nombre, la considera como
empleados.oficina=oficinas.oficina referencia externa, por eso no es necesario
AND ventas > objetivo * 0.55); cualificar ventas porque interpreta que es el
campo ventas de la tabla empleados.

Ejercicio 7

SELECT * Si un empleado no tiene ventas queremos que


FROM oficinas no sea tomado en cuenta, por eso aadimos
WHERE (objetivo * 0.5) <= ALL ( AND ventas IS NOT NULL. Adems esta
SELECT ventas FROM empleados solucin no vale porque salen las oficinas que
WHERE empleados.oficina = no tienen empleados.
oficinas.oficina AND ventas IS NOT Hay que aadir una condicin para que se
NULL); consideren slo las oficinas con empleados
como muestra la solucin 1.

Solucin 1
SELECT *
FROM oficinas
WHERE ((objetivo * 0.5) <= ALL (
SELECT ventas FROM empleados
WHERE empleados.oficina =
oficinas.oficina AND ventas IS NOT
NULL) )
AND ( EXISTS ( SELECT * FROM
empleados WHERE
empleados.oficina =
oficinas.oficina ) );

Solucin 2 Esta es otra posible solucin, calculamos la


SELECT * menor venta de los empleados de la oficina y si
FROM oficinas esta es mayor que el 50% del ojetivo de la
WHERE (objetivo * .5) <= (SELECT oficina quiere decir que todos los empleados de
MIN(ventas) FROM empleados esa oficina tienen ventas iguales o superiores.
WHERE empleados.oficina = Si la oficina no tiene empleados, la subconsulta
oficinas.oficina); no devuelve ninguna fila y como estamos
utilizando una comparacin simple el resultado
es nulo, luego no salen las oficinas que no
tienen empleados. Esta solucin es mucho ms
corta y elegante.

Ejercicio 8

SELECT *
FROM oficinas
WHERE objetivo > ( SELECT
SUM(cuota) FROM empleados
WHERE empleados.oficina =
oficinas.oficina);

6.1. Introduccin
Una subconsulta es una consulta que aparece dentro de otra consulta o subconsultas,
en la lista de seleccin o en la clusula WHERE o HAVING, originalmente no se podan
incluir en la lista de seleccin.
Una subconsulta se denomina tambin consulta o seleccin interna, mientras que la
instruccin que contiene la subconsulta es conocida como consulta o seleccin externa.

Aparece siempre encerrada entre parntesis y tiene la misma sintaxis que una sentencia
SELECT normal con alguna limitacin:
No puede incluir una clusula COMPUTE o FOR BROWSE y slo puede incluir una clusula
ORDER BY cuando se especifica tambin una clusula TOP.

Una subconsulta puede anidarse en la clusula WHERE o HAVING de una instruccin


externa SELECT, INSERT, UPDATE o DELETE, o bien en otra subconsulta. Se puede
disponer de hasta 32 niveles de anidamiento, aunque el lmite vara dependiendo de la
memoria disponible y de la complejidad del resto de las expresiones de la consulta. Hay
que tener en cuenta que para cada fila de la consulta externa, se calcula la subconsulta, si
anidamos varias consultas, el nmero de veces que se ejecutarn las subconsultas puede
dispararse!

Cuando la subconsulta aparece en la lista de seleccin de otra consulta, deber devolver


un solo valor, de lo contrario provocar un error.

Ejemplo de subconsulta: Listar los empleados cuya cuota no supere el importe vendido
por el empleado.

SELECT nombre

FROM empleados

WHERE cuota <= (SELECT SUM(importe)

FROM pedidos

WHERE rep = numemp);

Por cada fila de la tabla de empleados (de la consulta externa) se calcula la subconsulta
y se evala la condicin, por lo que utilizar una subconsulta puede en algunos casos
ralentizar la consulta, en contrapartida se necesita menos memoria que una composicin
de tablas.
Muchas de las instrucciones Transact-SQL que incluyen subconsultas se pueden formular
tambin utilizando composiciones de tablas. Otras preguntas se pueden formular slo con
subconsultas.
En Transact-SQL, normalmente no hay una regla fija en cuanto a diferencias de rendimiento
entre una instruccin que incluya una subconsulta y una versin semnticamente
equivalente que no la incluya.
Podremos utilizar una subconsulta siempre y cuando no se quiera que aparezcan en el
resultado columnas de la subconsulta ya que si una tabla aparece en la subconsulta y no
en la consulta externa, las columnas de esa tabla no se pueden incluir en la salida (la lista
de seleccin de la consulta externa).

Tenemos tres tipos de subconsultas:

Las que devuelven un solo valor, aparecen en la lista de seleccin de la consulta


externa o con un operador de comparacin sin modificar.
Las que generan una columna de valores, aparecen con el operador IN o con
un operador de comparacin modificado con ANY, SOME o ALL.
Las que pueden generar cualquier nmero de columnas y filas, son utilizadas en
pruebas de existencia especificadas con EXISTS.

A lo largo del tema las estudiaremos todas.

Antes de terminar con la introduccin queda comentar el concepto de referencia externa


muy til en las subconsultas.
A menudo, es necesario, dentro del cuerpo de una subconsulta, hacer referencia al valor de
una columna en la fila actual de la consulta externa, el nombre de columna de la consulta
externa dentro de la subconsulta recibe el nombre de referencia externa, ya que hace
referencia a una columna externa.
En el ejemplo anterior numemp es una referencia externa, no es una columna del origen de
datos de la subconsulta (pedidos), es una columna del origen de la consulta externa
(empleados).
Hay que tener en cuenta de cmo se ejecuta la consulta; por cada fila de la consulta externa
se calcula el resultado de la subconsulta y se evala la comparacin.
En el ejemplo, se coge el primer empleado (numemp= 101, por ejemplo) y se calcula la
subconsulta sustituyendo numemp por el valor 101, se calcula la suma de los pedidos del
rep = 101, y el resultado se compara con la cuota de ese empleado, y as se repite el proceso
con todas las filas de empleados.

El nombre de una columna dentro de la subconsulta se presupone del origen de datos


de la subconsulta y, slo si no se encuentra en ese origen, la considera como columna
externa y la busca en el origen de la consulta externa.
Por ejemplo:

SELECT oficina, ciudad

FROM oficinas

WHERE objetivo > (SELECT SUM(ventas)

FROM empleados

WHERE oficina = oficina);

La columna oficina se encuentra en los dos orgenes (oficinas y empleados) pero esta
consulta no dar error (no se nos pedir cualificar los nombres como pasara en una
composicin de tablas), dentro de la subconsulta se considera oficina el campo de la
tabla empleados. Con lo que comparara la oficina del empleado con la misma oficina del
empleado y eso no es lo que queremos, queremos comparar la oficina del empleado con la
oficina de oficinas, lo escribiremos pues as para forzar a que busque la columna en la
tabla oficinas.

SELECT oficina, ciudad

FROM oficinas

WHERE objetivo > (SELECT SUM(ventas)

FROM empleados

WHERE oficina = oficinas.oficina);

6.2. Subconsultas de resultado nico


Existen subconsultas que deben obligatoriamente devolver un nico valor, son las que
aparecen en la lista de seleccin de la consulta externa o las que aparecen en WHERE o
HAVING combinadas con un operador de comparacin sin modificar.

Los operadores de comparacin sin modificar son los operadores de comparacin que
vimos con la clusula WHERE.

Sintaxis:

<expresion> {=|<>|!=|>|>=|!>|<|<=|!<} <subconsulta>


En este caso la segunda expresin ser una subconsulta, con una sola columna en la
lista de seleccin y deber devolver una nica fila como mucho.
Ese valor nico ser el que se compare con el resultado de la primera expresin.
Si la subconsulta no devuelve ninguna fila, la comparacin opera como si la segunda
expresin fuese nula.
Si la subconsulta devuelve ms de una fila o ms de una columna, da error.
Ejemplo:

SELECT nombre

FROM empleados

WHERE cuota <= (SELECT SUM(importe)

FROM pedidos

WHERE rep = numemp);

La subconsulta devuelve una sola columna y como mucho una fila ya que es una consulta
de resumen sin clusula GROUP BY.

Para practicar puedes realizar este Ejercicio Subconsultas de resultado nico.

6.3. Subconsultas de lista de valores


Otro tipo de subconsultas son las que devuelven una lista de valores en forma de una
columna y cero, una o varias filas.
Estas consultas aparecen en las clusulas WHERE o HAVING combinadas con el operador
IN o con comparaciones modificadas.

6.4. El operador IN con subconsulta


<expresion> IN subconsulta

IN examina si el valor de expresion es uno de los valores incluidos en la lista de valores


generados por la subconsulta.

La subconsulta tiene que generar valores de un tipo compatible con la expresin.

Ejemplo:

SELECT *

FROM empleados

WHERE oficina IN (SELECT oficina

FROM oficinas

WHERE region = 'Este');

Por cada empleado se calcula la lista de las oficinas del Este (n de oficina) y se evala
si la oficina del empleado est en esta lista. Obtenemos pues los empleados de oficinas del
Este.

numemp nombre edad oficina titulo contrato jefe cuota ventas


101 Antonio Viguer 45 12 representante 1986-10-20 104 30000,00 30500,00
103 Juan Rovira 29 23 representante 1987-03-01 104 27500,00 28600,00
104 Jos Gonzlez 33 23 dir ventas 1987-05-19 106 20000,00 14300,00
105 Vicente Pantalla 37 13 representante 1988-02-12 104 35000,00 36800,00
106 Luis Antonio 52 11 dir general 1988-06-14 NULL 27500,00 29900,00

Si la subconsulta no devuelve ninguna fila:

SELECT *

FROM empleados

WHERE oficina IN (SELECT oficina

FROM oficinas

WHERE region = 'Otro');

La lista generada est vaca por lo que la condicin IN devuelve FALSE y en este caso
no sale ningn empleado.

Muchas veces la misma pregunta se puede resolver mediante una composicin de tablas.

SELECT empleados.*

FROM Empleados INNER JOIN oficinas ON empleados.oficina =


oficinas.oficina

WHERE region = 'Este';

Esta sentencia es equivalente. En el resultado no queremos ver ninguna columna de la


tabla oficinas, el JOIN lo tenemos slo para la pregunta, en este caso pues se puede sustituir
por una subconsulta.

Si combinamos el operador IN con NOT obtenemos el operador NOT IN.

<expresion> NOT IN subconsulta

Devuelve TRUE si el valor de la expresin no est en la lista de valores devueltos por la


subconsulta.

SELECT *

FROM empleados

WHERE oficina NOT IN (SELECT oficina

FROM oficinas

WHERE region = 'Este');

Devuelve los empleados cuya oficina no est en la lista generada por la subconsulta, es
decir empleados que trabajan en oficinas que no son del Este.

OJO con NOT IN.


Hay que tener especial cuidado con los valores nulos cuando utilizamos el operador NOT
IN porque el resultado obtenido no siempre ser el deseado por ejemplo:

* En la consulta anterior no salen los empleados que no tienen oficina ya que para esos
empleados la columna oficina contiene NULL por lo que no se cumple el NOT IN.
* Si la subconsulta no devuelve ninguna fila, la condicin se cumplir para todas las filas
de la consulta externa, en este caso todos los empleados.

* Si la subconsulta devuelve algn valor NULL, la condicin NOT IN es NULL lo que nos
puede ocasionar algn problema.
Por ejemplo, queremos obtener las oficinas que no estn asignadas a ningn empleado.

SELECT *

FROM Oficinas

WHERE oficina NOT IN (SELECT oficina

FROM empleados);

Esta consulta no devuelve ninguna fila cuando s debera ya que hay oficinas que nos
estn asignadas a ningn empleado. El problema est en que la columna oficina de la tabla
empleados admite nulos por lo que la subconsulta devuelve valores nulos en todos los
empleados que no estn asignados a ninguna oficina. Estos valores nulos hacen que no se
cumpla el NOT IN. La solucin pasa por eliminar estos valores molestos:

SELECT *

FROM Oficinas

WHERE oficina NOT IN (SELECT oficina

FROM empleados

WHERE oficina IS NOT NULL);

En el primer ejemplo no tenemos ese problema porque la columna oficina en oficinas no


admite nulos.

A diferencia de IN, NOT IN no siempre puede resolverse con una composicin:

SELECT numemp AS [IN]

FROM empleados

WHERE numemp IN (SELECT rep

FROM pedidos

WHERE fab = 'ACI');

Se puede resolver con una composicin:

SELECT DISTINCT empleados.numemp AS [=]

FROM Empleados INNER JOIN pedidos ON numemp = rep

WHERE fab = 'ACI';

En este caso, como un empleado puede tener varios pedidos hay que aadir DISTINCT
para eliminar las repeticiones de empleados (si un empleado tiene varios pedidos de ACI
aparecera varias veces).
Sin embargo esta sentencia con NOT IN, queremos los empleados que no tienen pedidos
de ACI:

SELECT numemp AS [NOT IN]

FROM empleados

WHERE numemp NOT IN (SELECT rep

FROM pedidos

WHERE fab = 'ACI');

No se puede resolver con una composicin:

SELECT DISTINCT empleados.numemp AS [<>]

FROM Empleados INNER JOIN pedidos ON numemp = rep

WHERE fab <> 'ACI';

Esta consulta devuelve los empleados que tienen pedidos que no son de ACI, pero un
empleado puede tener pedidos de ACI y otros de otros fabricantes y por estos otros saldra
en el resultado cuando s tiene pedidos de ACI y no debera salir.
Hay que tener mucho cuidado con este tipo de preguntas.

Objetivo
Realizar consultas que incluyan una subconsulta en la clusula WHERE, introducida por
el operador IN.

Ejercicio paso a paso


Listar los clientes (nombre) que han remitido pedidos del fabricante ACI y nproducto
que empiece por 4100, entre enero y el 15 de abril de 1990.

SELECT numclie,nombre

FROM clientes

WHERE numclie IN (SELECT clie FROM pedidos

WHERE fab = 'ACI'

AND producto LIKE '4100%' AND fechapedido >= '01/01/90' AND fechapedido
<'16/04/90');

Resultado:

numclie nombre
2102 Alvaro Rodrguez
2118 Junpero Alvarez

Listar los empleados (numemp, nombre) que han realizado un pedido que represente
ms del 1% de su cuota.

SELECT numemp, nombre


FROM empleados

WHERE numemp IN (SELECT rep FROM pedidos

WHERE importe > cuota* 0.01);

Resultado:

numemp nombre
105 Vicente Pantalla
107 Jorge Gutirrez
109 Mara Sunta