SUBCONSULTAS Consulta SELECT que aparece dentro de otra consulta SELECT y que obtiene unos resultados intermedios que se utilizan para realizar una comparación en el WHERE o en el HAVING. select distinct c.nombre from clientes c, facturas f where c.codcli = f.codcli and f.dto = ( select max(dto) from facturas ); La subconsulta sólo devuelve un valor II18-Universitat Jaume I 1 SUBCONSULTAS select pr.nombre from pueblos pu, provincias pr where pu.codpro = pr.codpro group by pr.codpro, pr.nombre having count(*) > ( select 0.5 * max(count(*)) from pueblos p group by p.codpro ); La subconsulta sólo devuelve un valor II18-Universitat Jaume I 2
SUBCONSULTAS select pr.nombre from pueblos pu, provincias pr where pu.codpro = pr.codpro group by pr.codpro, pr.nombre having count(*) > all ( select 0.5 * count(*) from pueblos p group by p.codpro ); La subconsulta devuelve varios valores II18-Universitat Jaume I 3 OPERADORES IN Y EXISTS select codcli, nombre Conjunto from clientes independiente where codcli in ( select codcli de valores from facturas where iva = 16 ); select c.codcli, c.nombre Referencia externa from clientes c where exists ( select * from facturas f where f.codcli = c.codcli and iva = 16 ); II18-Universitat Jaume I 4
Cuándo son necesarias? select c.codcli, c.nombre from clientes c, facturas f where c.codcli = f.codcli and iva = 16 ); Seleccionar los clientes que en todas sus facturas tienen un IVA diferente del 16%... II18-Universitat Jaume I 5 OPERADORES IN Y EXISTS Conjunto select codcli, nombre independiente from clientes de valores where codcli not in ( select codcli from facturas where iva = 16 ); select c.codcli, c.nombre Referencia externa from clientes c where not exists ( select * from facturas f where f.codcli = c.codcli and iva = 16 ); II18-Universitat Jaume I 6
OPERADORES IN Y EXISTS select codcli, nombre from clientes where codcli in ( select codcli from facturas ) and codcli not in ( select codcli from facturas where iva = 16 ); Clientes con alguna factura y que en todas sus facturas tienen un IVA diferente de 16 II18-Universitat Jaume I 7 OPERADORES IN Y EXISTS Doble Negación select codcli, nombre from clientes where codcli not in ( select codcli from facturas where IVA = 10 ) and codcli in ( select codcli from facturas ); Clientes (con alguna factura) que en todas sus facturas tienen un IVA diferente de 10 8
Clientes que NO tienen ninguna factura con 16% de IVA. SELECT codcli FROM clientes MINUS SELECT codcli WHERE iva = 16; Incluye a los clientes que nunca han comprado II18-Universitat Jaume I 9 Clientes que NO tienen ninguna factura con 16% de IVA, pero han comprado alguna vez. SELECT distinct codcli MINUS SELECT codcli WHERE iva = 16; II18-Universitat Jaume I 10
NÚMERO de clientes que NO tienen ninguna factura con 16% de IVA, pero han comprado alguna vez. SELECT COUNT(distinct f1.codcli) f1 WHERE NOT EXISTS ( SELECT * f2 WHERE f2.codcli = f1.codcli AND f2.iva = 16 ); referencia externa II18-Universitat Jaume I 11 Número de clientes que NO tienen ninguna factura con 16% de IVA, pero han comprado alguna vez. sin referencia externa SELECT COUNT(distinct f.codcli) f WHERE f.codcli NOT IN ( SELECT codcli WHERE iva = 16 ); NOT IN es como decir < > ALL II18-Universitat Jaume I 12
Número de clientes que NO tienen ninguna factura con 16% de IVA, pero han comprado alguna vez. SELECT COUNT(distinct f1.codcli) f1 WHERE 16 <> ALL ( SELECT NVL(f2.iva,0) f2 WHERE f2.codcli = f1.codcli); referencia externa otra vez II18-Universitat Jaume I 13 Todas estas sentencias consideran los clientes repetidamente: tantas veces como facturas tengan. Para mejorarlas debemos buscar sentencias equivalentes que consideren cada cliente una sola vez. II18-Universitat Jaume I 14
Esta es la primera versión que vimos: select codcli, nombre from clientes where codcli in ( select codcli from facturas ) and codcli not in ( select codcli from facturas where iva = 16 ); II18-Universitat Jaume I 15 Aprovechamos la sentencia que usa MINUS: SELECT COUNT(*) FROM clientes WHERE codcli IN ( SELECT codcli MINUS SELECT codcli WHERE iva = 16 ); II18-Universitat Jaume I 16
Aprovechamos el conocimiento: el IVA máximo es 16, si el máximo IVA pagado por un cliente es menor que 16 entonces nunca ha pagado el 16. SELECT COUNT(COUNT(*)) GROUP BY codcli HAVING MAX(NVL(iva,0)) < 16; II18-Universitat Jaume I 17 Otra consulta: Número de clientes que en todas sus facturas tienen un 16% de IVA. SELECT COUNT(*) FROM clientes WHERE codcli NOT IN ( SELECT codcli WHERE NVL(iva, 0) <> 16 ) AND codcli IN ( SELECT codcli ); II18-Universitat Jaume I 18
Número de clientes que en todas sus facturas tienen un 16% de IVA. SELECT COUNT(*) FROM clientes c WHERE 16 = ALL ( SELECT NVL(f.iva,0) f WHERE f.codcli = c.codcli ) AND codcli IN ( SELECT codcli ); II18-Universitat Jaume I 19 Número de clientes que en todas sus facturas tienen un 16% de IVA. SELECT COUNT(COUNT(*)) GROUP BY codcli HAVING MAX(NVL(iva,0))= 16 AND MIN(NVL(iva,0))= 16; II18-Universitat Jaume I 20
Número de clientes que en todas sus facturas tienen un 16% de IVA. SELECT COUNT(*) FROM clientes c WHERE codcli IN ( SELECT codcli WHERE iva = 16 MINUS SELECT codcli WHERE NVL(iva,0) <> 16 ); II18-Universitat Jaume I 21 Fecha de la factura con mayor importe. Sé cómo sacar el importe más grande: SELECT MAX(SUM(cant*precio)) FROM lineas_fac GROUP BY codfac; Puedo hacer una restricción sobre las facturas y quedarme con la que tiene este mismo importe... II18-Universitat Jaume I 22
... el cálculo del importe máximo será una subconsulta: SELECT f.fecha FROM lineas_fac l, facturas f WHERE l.codfac = f.codfac GROUP BY f.codfac, f.fecha HAVING SUM(l.cant*l.precio) = ( SELECT MAX(SUM(cant*precio)) FROM lineas_fac GROUP BY codfac ); II18-Universitat Jaume I 23 Fecha de la factura con mayor importe. Algunos SGBD no permiten usar MAX(COUNT(*)): SELECT f.fecha FROM lineas_fac l, facturas f WHERE l.codfac = f.codfac GROUP BY f.codfac, f.fecha HAVING SUM(l.cant*l.precio) >= ALL ( SELECT SUM(cant*precio) FROM lineas_fac GROUP BY codfac ); II18-Universitat Jaume I 24
Cuál de todas las versiones es más eficiente? Habría que probarlo... o ser un experto! El uso de subconsultas suele ser menos eficiente, pero no siempre ha de ser así. CONCLUSIÓN: hay que ser capaces de encontrar sentencias equivalentes. II18-Universitat Jaume I 25