prácticas BD1 2003-04 sesión 13 CONSULTAS ANIDADAS Objetivos: • Utilizar el resultado de una sentencia select para establecer las condiciones de otra sentencia select. Contenidos • Subqueries. • operadores de comparación escalar. • IN, ALL, ANY, [NOT]. • Resolución de requerimientos. CONSULTAS ANIDADAS (SUBQUERIES) En la condición de búsqueda de la orden select (en la cláusula where o en la having) también podemos: • comparar una expresión con el resultado de otra orden select • determinar si el valor de una expresión está incluido en los resultados de otra orden select • preguntar si una orden select ha seleccionado filas. Cuando una orden select se encuentra dentro de la cláusula where de otra select recibe el nombre de subconsulta (subquery). Por ejemplo : select descripción, créditos from asignaturas where créditos = ( select min(créditos) from asignaturas ) resultado: descripción Historia de la Informática créditos 4.5 En primer lugar se calcula la select anidada (entre paréntesis) y se obtiene el valor mínimo para la columna créditos de la tabla asignaturas. Con ese valor se compara tupla a tupla y se obtiene la asignatura (o asignaturas) cuya cantidad de créditos es igual al mínimo. sintaxis general de la subconsulta expresión op_comparación { ALL | [ ANY | SOME ] } ( orden select ) expresión [ NOT ] IN ( orden select ) [ NOT ] EXISTS ( orden select ) Los valores posibles a devolver por una orden select anidada son : • nada • un valor único (una fila y una columna), • un conjunto de valores (varias filas y una columna). 75 prácticas BD1 2003-04 Siempre que la subselect devuelva algo, únicamente será en una y nada más que una columna (salvo el operador EXISTS). DEVOLUCIÓN DE UN ÚNICO VALOR expresión op_comparación ( orden select ) Podemos utilizar los operadores de comparación para preguntar si el valor de una determinada expresión es mayor, menor, igual, etc. que el resultado de la subselect, siempre y cuando ésta devuelva una única fila y una única columna, es decir, un valor simple. En general serán órdenes select que calculan una función agregada (sum, min, max, avg, count). select descripción from asignaturas where créditos = ( select min(créditos) from asignaturas ) No sería correcto, porque la subselect devuelve más de una fila, la siguiente orden : select descripción from asignaturas where créditos = ( select créditos from asignaturas where créditos < 9 ) DEVOLUCIÓN DE UNA LISTA DE VALORES expresión op_comparación ALL | [ ANY | SOME ] ( orden select ) Cuando la tabla resultado contiene más de una fila (pero una única columna, insistimos) hay que utilizar un modificador para el operador de comparación. Nombre de la asignatura que tiene el mínimo número de créditos (es equivalente al primer ejemplo) : select descripción from asignaturas where créditos <= ALL ( select créditos from asignaturas ) resultado: descripción Historia de la Informática créditos 4.5 En este caso, el número en créditos de la asignatura tiene que ser menor o igual que todos (all) los valores obtenidos en la subconsulta (que es la relación de créditos de todas las asignaturas). 76 prácticas BD1 2003-04 Nombre de las asignaturas que no tienen el mínimo número de créditos : select descripción from asignaturas where créditos > ANY ( select créditos from asignaturas ) resultado: créditos 6 6 6 9 descripción Fundamentos de las Bases de Datos Diseño y Gestión de Bases de Datos Programación Concurrente Fundamentos de la Programación Serían todas aquellas asignaturas cuyos créditos superasen al menos a uno (any) de los valores devueltos por la subconsulta. El modificador some es equivalente a any. Otra forma de expresar el mismo requerimiento : select descripción from asignaturas where créditos != ( select min(créditos) from asignaturas ) Supongamos que deseamos obtener el nombre de los profesores que imparten una asignatura que no sea la máxima en número de créditos : select nombre from profesores p, asignaturas a, imparte i where p.dni = i.dni and i.asignatura = a.codigo and créditos < ANY ( select créditos from asignaturas ) resultado: nombre Eva Gómez Rafael Romero expresión [ NOT ] IN ( orden select ) También podemos consultar la pertenencia de un valor a la lista de valores devuelta por la subconsulta. Obtener todos los datos de los profesores que imparte alguna asignatura : select * from profesores where dni IN ( select dni from imparte ) O dicho de otra manera : datos de los profesores cuyo dni aparece en la tabla imparte. En este caso daría lo mismo procesar la orden : select p.* from profesores p, imparte i where p.dni = i.dni Se verá más clara la utilidad de este operador si preguntamos justo lo contrario. 77 prácticas BD1 2003-04 Obtener todos los datos de los profesores que no imparten asignaturas : select * from profesores where dni NOT IN ( select dni from imparte ) Por último, veamos que algunos de estos operadores son equivalentes : expresión IN (orden select) expresión NOT IN (orden select) 78 ≡ ≡ expresión =ANY (orden select) expresión !=ALL (orden select) prácticas BD1 2003-04 REQUERIMIENTOS S13 1. Obtener todos los datos de los vendedores a los que se les han solicitado más pedidos que a todos los demás. 2. Número y nombre de los vendedores que no ofertan ninguna pieza. 3. Número y nombre de los vendedores a los que se les ha solicitado algún pedido. 4. Número y nombre de los vendedores a los que no se les ha solicitado pedidos. 5. Nombre de la empresa que ofrece la pieza más barata de precio de suministro. 6. Número y descripción de la pieza más cara (precio de venta). 7. Para cada pieza que se ofrece en la lista de suministros, obtener el número de pieza, y sus precios unitarios máximo y mínimo, exceptuando aquellos suministrados por el vendedor número 1. 8. Número de pedido y precio total pagado del pedido más caro. 9. Número y nombre del vendedor al que se le ha solicitado el pedido más caro. 10. Número, descripción y precio de venta de los monitores que no han sido nunca solicitados. 11. Calcular, por cada número de vendedor, la cantidad de piezas distintas que ha vendido, para aquellos vendedores pertenecientes a la empresa con más proveedores. 12. Nombre de los suministradores que pueden suministrar al menos alguna de las piezas que puede suministrar el vendedor número 5. 13. Listar los vendedores que sean de la misma provincia que el vendedor número 100. 14. Obtener los nombres de los vendedores de la misma empresa que Luis García. 15. Número y descripción de las piezas cuyo precio medio de suministro esté por encima del mayor precio de compra pagado por ella. 16. Número, nombre, empresa en la que trabaja y número de piezas que puede suministrar el vendedor que tiene la media más alta de piezas servidas. 17. Nombre de la empresa con mayor importe de ventas. 18. Número y descripción de la pieza que ha sido pedida más veces. 19. Número y descripción de las piezas que pueden ser suministradas por proveedores de la Comunidad Valenciana o que pueden ser suministradas por el vendedor que ha realizado la menor venta (pedido de importe más bajo) 20. Número de vendedor, número de pieza y descuento para aquellas piezas cuyo precio de venta supere en más del 15% la media del precio de compra de los pedidos en los que aparece. 21. Cantidad de piezas a la venta de las que no tenemos información sobre sus posibles suministradores. 79 prácticas BD1 2003-04 SOLUCIONES S13 --1 select * from vendedor where numvend in (select numvend from pedido group by numvend having count(*) >= all(select count(*) from pedido group by numvend)) --2 select numvend, nomvend from vendedor where numvend not in (select numvend from preciosum) order by nomvend En A.R. (VENDEDOR[numvend] ∼ PRECIOSUM[numvend]) >< VENDEDOR[numvend, nomvend] En C.R.T. {V.numvend, V.nomvend / VENDEDOR(V) ∧ ∃ PR(PRECIOSUM(PR) ∧ PR.numvend=V.numvend)} --3a select v.numvend, nomvend from vendedor v, pedido p where v.numvend = p.numvend order by nomvend En A.R. VENDEDOR >< PEDIDO [numvend, nomvend] En C.R.T. {V.numvend, V.nomvend / VENDEDOR(V) ∧ ∃ P(PEDIDO(P) ∧ P.numvend=V.numvend)} --3b select numvend, nomvend from vendedor where numvend in (select numvend from pedido) order by nomvend --11 select v.numvend,count(distinct numpieza) npiezas from vendedor v, pedido p, linped l where v.numvend=p.numvend and p.numpedido=l.numpedido and nombrecomer in (select nombrecomer from vendedor group by nombrecomer having count(*) >= all (select count(*) from vendedor group by nombrecomer)) group by v.numvend order by v.numvend --15 select p.numpieza, nompieza,avg(preciounit),max(preciocompra) from pieza p, preciosum ps, linped l where p.numpieza=ps.numpieza and ps.numpieza=l.numpieza group by p.numpieza, nompieza having avg(preciounit)>= (select max(preciocompra) from linped where linped.numpieza=p.numpieza) 80 sesión 14 CONSULTAS ANIDADAS II Contenidos • El operador EXISTS. • Resolución de requerimientos. EL OPERADOR EXISTS [ NOT ] EXISTS ( orden select ) El operador exists nos informa si una subconsulta ha devuelto algún resultado, o lo que es lo mismo, si la tabla resultado tiene alguna fila. Exists devuelve verdadero si hay al menos una tupla en la relación derivada y falso si la relación derivada es vacía. Supongamos que queremos conocer si algún profesor imparte todas las asignaturas : select nombre from profesores p where not exists ( select código from asignaturas a where not exists ( select asignatura from imparte i where i.asignatura=a.código and p.dni=i.dni ) ) Vamos a leer el requerimiento siguiendo las apariciones del operador exists dentro de las sucesivas órdenes select : Nombre de los profesores tales que no hay ninguna asignatura que no imparta él. Supongamos que la forma que tiene el SGBD de resolver esta sentencia es la siguiente : • En la primera select recorremos la tabla de profesores. • Para cada profesor, la segunda select recorre la tabla de asignaturas. • Para cada profesor y asignatura comprueba que el primero imparte la segunda. Una vez que ha fijado el profesor y la asignatura, la última subconsulta dará como resultado verdadero si la imparte y falso en caso contrario (devolverá una tupla o no devolverá nada). Supongamos un profesor que no imparte al menos una de las asignaturas de nuestra base de datos. Cuando el SGBD esté resolviendo la última subselect para ese profesor y esa asignatura, como no están relacionados, no devolverá ninguna tupla : el resultado del segundo exists es falso, y, como está negado, finalmente verdadero (ese profesor no imparte esa asignatura). Por lo tanto, para la primera subselect, ya existe una asignatura que obtiene en la cláusula where un valor verdadero : esa asignatura saldrá en la tabla resultado. Como ésta última tiene al menos una fila, el primer exists será verdadero, y, como está negado, finalmente falso. El profesor no imparte todas las asignaturas de nuestra base de datos. Un profesor que imparta todas las asignaturas obtendrá siempre una fila en la última subselect y, por lo tanto, ninguna asignatura aparecerá como resultado de la primera subselect, el correspondiente exists será falso, y por efecto del operador de negación la condición será cierta : ese profesor aparecerá en la solución. En nuestra base de datos Ejemplo no hay ningún profesor que imparta todas las asignaturas. prácticas Aunque puede inducir a error, por su traducción intuitiva del inglés al español, no se deben confundir nunca los operadores IN y EXISTS : el primero devuelve una lista de valores, mientras que el segundo devuelve un valor de verdad; la sintaxis también es muy diferente. 82 prácticas REQUERIMIENTOS S14 1. Nombre de los vendedores que pueden suministrar todas las piezas. 2. Nombre de los alfabéticamente. 3. Numero y descripción de las piezas que se han solicitado en todos los pedidos del vendedor 1. 4. Nombre de las empresas que cumplen que todos sus vendedores son de la Comunidad Valenciana, ordenadas alfabéticamente. 5. Número y nombre de todos los vendedores de la ciudad de Alicante. 6. Empresas que no han servido ninguna pieza. 7. Empresas que han servido la(s) pieza(s) de mayor precio de venta. 8. Numero de los pedidos cuyas piezas tienen todas un precio de venta mayor que la mitad del precio máximo de venta. 9. Obtener todos los datos de los vendedores que sirvieron los pedidos del requerimiento anterior. vendedores que no pueden suministrar ninguna pieza, ordenados 10. Número y nombre de los vendedores que han servido algún pedido (utilizando obligatoriamente EXISTS). 11. Número y nombre de la pieza de menor precio de suministro (utilizando EXISTS). 12. Nombre de los vendedores a los que se les haya solicitado más de dos pedidos (utilizando subconsultas). 13. Número de pedido, fecha y número de vendedor del pedido más caro (utilizando subconsultas). 83 prácticas SOLUCIONES S14 --1 select nomvend from vendedor v where not exists (select * from pieza pz where not exists (select * from preciosum where numvend = v.numvend and numpieza = pz.numpieza)) En A.R. ((PRECIOSUM [numvend, numpieza] ÷ PIEZA[numpieza]) >< VENDEDOR) [nomvend] En C.R.T. { V.nomvend / VENDEDOR(V) ∧ ∀P (PIEZA(P) ⇒ ∃ PR (PRECIOSUM(PR) ∧ PR.numvend=V.numvend ∧ PR.numpieza=P.numpieza ))} --2 select nomvend from vendedor where numvend not in (select numvend from preciosum) order by nomvend --2 select nomvend from vendedor v where not exists (select * from preciosum where numvend = v.numvend) order by nomvend En A.R. ((VENDEDOR[numvend] ∼ PRECIOSUM[numvend]) >< VENDEDOR)[nomvend] En C.R.T. {V.nomvend / VENDEDOR(V) ∧ ∃ PR(PRECIOSUM(PR) ∧ PR.numvend=V.numvend)} --3 select numpieza, nompieza from pieza pz where not exists (select * from pedido pd where numvend=1 and not exists (select * from linped l where pd.numpedido=l.numpedido and pz.numpieza=l.numpieza)) En A.R. ((LINPED [numpieza, numpedido] ÷ (PEDIDO donde numvend=1)[numpedido]) >< PIEZA) [numpieza, nompieza] En C.R.T. { P.numpieza, P.nompieza / PIEZA(P) ∧ ∀PD (PEDIDO(PD) ∧ PD.numvend=1 ⇒ ∃ LP (LINPED(LP) ∧ LP.numpedido=PD.numpedido ∧ LP.numpieza=P.numpieza ))} --4 select distinct nombrecomer from vendedor v where not exists (select * from vendedor where nombrecomer = v.nombrecomer and provincia not in ('ALICANTE','CASTELLON','VALENCIA')) order by nombrecomer En A.R. VENDEDOR[nombrecomer] ∼ (VENDEDOR donde provincia<>ALICANTE or provincia<>CASTELLON or provincia<>VALENCIA)[nombrecomer] En C.R.T. { V.nombrecomer / VENDEDOR(V) ∧ ∀ V2 (VENDEDOR(V2) ∧ V2.nombrecomer=V.nombrecomer ⇒ (V2.provincia=ALICANTE ∨ V2.provincia=CASTELLON ∨ V2.provincia=VALENCIA))} O bien { V.nombrecomer / VENDEDOR(V) ∧ ∃ V2 (VENDEDOR(V2) ∧ V2.nombrecomer=V.nombrecomer ∧ V2.provincia<>ALICANTE ∧ V2.provincia<>CASTELLON ∧ V2.provincia<>VALENCIA))} 84