Interrogazioni Nidificate 29/12/2018
Subquery Una subquery è un comando Select, racchiuso tra parentesi tonde, inserito all’interno di un comando SQL, per esempio un’altra Select. Le subquery possono essere utilizzate nei seguenti casi: In espressioni di confronto In espressioni di confronto quantificato In espressioni IN In espressioni EXISTS Nel calcolo di espressioni 29/12/2018
Tipi di subquery Tre tipologie: scalare, di colonna, di tabella Subquery Scalare: è un comando Select che restituisce un solo valore. SELECT Max(Cilindrata) FROM Veicoli SELECT Cod_Categoria FROM Veicoli Where Targa=“123456” Subquery di Colonna: è un comando Select che restituisce una colonna SELECT cod_categoria FROM Veicoli Subquery di Tabella: è un comando Select che restituisce una tabella SELECT Targa, Cod_mod, Posti FROM Veicoli 29/12/2018
Subquery in espressioni di confronto Categorie Cod_cat Nome_cat Veicoli Targa Cod_mod Categoria Cilindrata Cod_comb. cav.Fisc Velocita Posti Imm Vogliamo trovare tutti i veicoli della categoria “Autovettura” Select Veicoli.* From Categorie, Veicoli Where Categoria=Cod_cat and Nome_Cat = ‘Autovettura’ Mediante Join Select * From Veicoli Where Categoria = (Select cod_cat From Categorie Where nome_cat=‘Autovettura’) Mediante Subquery 29/12/2018
Scelta tra Join e subquery In questo caso la scelta tra l’una o l’altra forma è una questione di gusto. Mentre l’uso della join è più sintetico, l’uso delle subquery è più intuitivo e leggibile. 29/12/2018
Regole della subquery di confronto La subquery deve essere di tipo scalare, ossia deve restituire un singolo valore La subquery deve essere inserita DOPO l’operatore di confronto Non è ammesso il confronto tra due subquery Nelle subquery non è possibile utilizzare le clausole Having e Group By. Tali clausole possono essere usate nella select che le contiene 29/12/2018
Uso di subquery in espressioni di confronto Ricordiamo che nelle select semplici non è possibile utilizzare contemporaneamente funzioni di gruppo e funzioni su singole righe. Questo viene reso possibile mediante l’uso delle subquery. 29/12/2018
Uso di subquery in espressioni di confronto Esempio: tutti i veicoli di cilindrata superiore alla cilindrata media. Select * From Veicoli Where Cilindrata> (select AVG(Cilindrata) From Veicoli) Esempio: I veicoli di cilindrata massima. Select * From Veicoli Where Cilindrata = (Select max(cilindrata) From Veicoli) 29/12/2018
Subquery + Join Veicoli Modelli Targa Cod_mod Categoria Cilindrata Cod_combust. cav.Fisc Velocita Posti Imm Modelli Cod_Mod Nome_Mod Cod_Fab Num_versioni Selezionare i modelli che presentano più versioni del numero minimo di versioni dei veicoli a benzina (Cod_combustibile=’01’). Select * From Modelli Where num_versioni > (Select min (num_versioni) From Veicoli, Modelli Where Veicoli.cod_mod=Modelli.cod_mod And cod_combust=‘01’) 29/12/2018
Esercizi Esercizio 1: Trovare tutti gli ordini del negozio Compolegno SELECT ord_cod FROM Ordini WHERE neg_cod= (SELECT neg_cod FROM Negozi WHERE neg_nome= ‘Compolegno’) SELECT ord_cod FROM Ordini, Negozi WHERE Negozi.neg_cod=Ordini.Neg_cod AND neg_nome= ‘Compolegno’ 29/12/2018
Esercizi Esercizio 2: Selezionare i nomi dei componenti meno utilizzati nelle composizioni, ovvero che compaiono meno della media nella composizione dei vari articoli. Select distinct com_descrizione From Componenti NATURAL JOIN Compart Where compart_qta < (select AVG(compart_qta) from Compart) 29/12/2018
Esercizi Esercizio 3: Selezionare i componenti il cui costo è superiore al prezzo dell’articolo T400. Select com_descrizione FROM Componenti WHERE com_costo>(Select art_prezzo From Articoli WHERE art_cod=‘T400’) 29/12/2018
Esercizi Esercizio 4: Selezionare gli articoli che costano meno del componente col prezzo più alto. Select articoli.* From Articoli Where art_prezzo < (Select max(com_costo) From Componenti) 29/12/2018
Subquery in espressioni di confronto quantificato Con le subquery viste finora non era possibile effettuare il confronto con tutti i valori di una colonna. Per fare questo è possibile utilizzare gli operatori di confronto quantificato, costituiti da un operatore di confronto seguito dalle parole chiave ALL ed ANY, seguite da una subquery. ANY: il predicato è vero se almeno uno dei valori restituiti dalla subquery soddisfa la condizione ALL: il predicato è vero se tutti i valori restituiti dalla subquery soddisfano la condizione 29/12/2018
Subquery di confronto quantificato, regole La subquery deve essere una subquery di colonna La subquery deve essere inserita DOPO l’operatore di confronto quantificato Non è ammesso il confronto fra due subquery Nella subquery non è possibile utilizzare le clausole having e group by 29/12/2018
Subquery di confronto quantificato, esempio 1 Veicoli Targa Cod_mod Categoria Cilindrata Cod_combust. cav.Fisc Velocita Posti Imm Selezionare tutti i veicoli con cilindrata inferiore ad almeno una delle cilindrate dei veicoli con combustibile 02 (quindi inferiore alla più alta di queste cilindrate). Select * FROM Veicoli Where cilindrata < Any (select cilindrata From Veicoli Where cod_combust=’02’) Select * From Veicoli Where cilindrata< (select max(cilindrata) From Veicoli Where cod_combust=’02’ ) 29/12/2018
Subquery di confronto quantificato, esempio Veicoli Targa Cod_mod Categoria Cilindrata Cod_combust. cav.Fisc Velocita Posti Imm Selezionare tutti i veicoli con cilindrata inferiore a tutte le cilindrate dei veicoli con combustibile 02 (quindi inferiore alla più bassa di queste cilindrate) Select * FROM Veicoli Where cilindrata < All (select cilindrata From Veicoli Where cod_combust=’02’) Select * From Veicoli Where cilindrata< (select min(cilindrata) From Veicoli Where cod_combust=’02’) 29/12/2018
=ANY e <>ALL In particolare le forme =ANY (equivalentemente IN) e <>ALL (equivalentemente NOT IN), forniscono un modo alternativo per realizzare intersezione e differenza dell’algebra relazionale. Esempio: intersezione dei modelli con cilindrata inferiore a 1400 e quelli con codice fabbrica uguale a 001 Select cod_modello From Veicoli Where cilindrata < 1400 and Cod_modello = ANY [IN] (select cod_modello Where cod_fab=‘001’) 29/12/2018
<>ANY (NOT IN) Differenza fra le due tabelle precedenti: modelli con cilindrata inferiore a 1400 che non sono prodotti dalla fabbrica dal codice 001 Select cod_modello From Veicoli Where cilindrata<1400 and cod_modello<> ANY [NOT IN] (Select cod_modello Where cod_fabbrica=‘001’ 29/12/2018
Esercizio Selezionare gli articoli con prezzo inferiore al costo di un qualsiasi componente, senza utilizzare la funzione max. Select art_descrizione From Articoli Where art_prezzo< Any (select com_costo From Componenti) 29/12/2018
Esercizio Selezionare gli articoli con prezzo inferiore al costo di tutti i componenti, senza usare la funzione min. Select * From Articoli Where art_prezzo < All (Select com_costo From Componenti) 29/12/2018
Esercizio Trovare i codici degli articoli in cui c’è almeno un componente non prodotto in laboratori Select distinct art_cod From Compart Where com_cod IN (Select com_cod From Componenti Where Lab_cod IS NULL) 29/12/2018
Esercizio Elencare tutte le città in cui sono presenti sia laboratori che negozi Select distinct lab_citta From Laboratori Where lab_citta IN (Select Neg_citta From Negozi) 29/12/2018
Subquery in espressioni EXISTS Tramite il predicato EXISTS è possibile effettuare il controllo sull’esistenza di righe che soddisfano specifiche condizioni. In questo caso la subquery è una subquery di tabella. 29/12/2018
Esempio Categorie Cod_cat Nome_cat Veicoli Targa Cod_mod Categoria Cilindrata Cod_comb. cav.Fisc Velocita Posti Imm Esempio: trovare i nomi di tutte le categorie per cui è presente almeno un veicolo Select Nome_cat From Categorie Where EXISTS (Select * From Veicoli Where categorie.cod_cat= Veicoli.categoria) 29/12/2018
Clausola NOT EXISTS Per verificare l’assenza di righe che rispondono a una determinata condizione è definita la forma negativa NOT EXISTS 29/12/2018
Esempio Categorie Cod_cat Nome_cat Veicoli Targa Cod_mod Categoria Cilindrata Cod_comb. cav.Fisc Velocita Posti Imm Esempio: tutte le categorie per cui non è presente nessun veicolo Select Cat_nome From Categorie Where NOT EXISTS (Select * From Veicoli where Categorie.Cod_cat= Veicoli. categoria) 29/12/2018
EXISTS e NOT EXISTS Notare che nelle due query precedenti nelle subquery si fa riferimento alla tabella Categorie che non è presente nella clausola FROM. Questo è possibile perché in una subquery sono visibili le variabili della query principale. Le condizioni EXISTS e NOT EXISTS sono delle forme semplificate di subquery di confronto quantificato. 29/12/2018
EXISTS, =ANY, IN Select Nome_cat From Categorie Where EXISTS (Select * From Veicoli Where categorie.cod_cat= Veicoli.cod_categoria) Select Nome_cat From Categorie Where Cat_cod =ANY (Select categorie From Veicoli) Select Nome_cat From Categorie Where Cat_cod IN (Select categorie From Veicoli) 29/12/2018
NOT EXISTS, <>ALL, NOT IN Select Cat_nome From Categorie Where NOT EXISTS (Select * From Veicoli where Categorie.Cod_categoria= Veicoli. categoria) Select Cat_nome From Categorie Where cat_cod <>ALL (Select Categorie From Veicoli) Select Cat_nome From Categorie Where cat_cod NOT IN (Select Categorie From Veicoli) 29/12/2018
Semantica delle espressioni “correlate” La query più interna può usare variabili della query esterna L’interrogazione interna viene eseguita una volta per ciascuna ennupla dell’interrogazione esterna Esempio: trovare tutti gli studenti che hanno un omonimo: SELECT * FROM Studenti S WHERE EXISTS (SELECT * FROM Studenti S2 WHERE S2.Nome = S.Nome AND S2.Cognome = S.Cognome AND S2.Matricola <> S.Matricola) Matricola Cognome Nome 29/12/2018
Semantica delle espressioni “correlate”, 2 Esempio: trovare tutti gli studenti che NON hanno un omonimo: SELECT * FROM Studenti S WHERE NOT EXISTS (SELECT * FROM Studenti S2 WHERE S2.Nome = S.Nome AND S2.Cognome = S.Cognome AND S2.Matricola <> S.Matricola) 29/12/2018
Esempio Le persone che hanno almeno un figlio SELECT * FROM Persone WHERE EXISTS ( SELECT * FROM Paternita WHERE Padre = Nome) OR EXISTS ( SELECT * FROM Maternita WHERE Madre = Nome) 29/12/2018
Esempio I padri i cui figli guadagnano tutti più di venti milioni SELECT distinct Padre FROM Paternita Z WHERE NOT EXISTS ( SELECT * FROM Paternita W, Persone WHERE W.Padre = Z.Padre AND W.Figlio = Nome AND Reddito <= 20) 29/12/2018
Esercizio Trovare tutti i componenti prodotti nei laboratori (usando EXISTS) Select Com_descrizione From Componenti Where EXISTS (Select * From Laboratori Where Componenti.lab_cod=Laboratori.lab_cod) 29/12/2018
Esercizio Trovare tutti gli articoli per cui non vi sono ordini Select * From Articoli Where NOT EXISTS (Select * From Ordart Where Articoli.art_cod=Ordart.art_cod) 29/12/2018
Subquery nel calcolo di espressioni Le subquery oltre che essere usate all’interno della clausola WHERE, possono anche essere utilizzate nel calcolo di espressioni, dunque per definire colonne. Esempio: Per ogni veicolo rappresentare la targa, la cilindrata e la differenza fra la cilindrata e la cilindrata minima Veicoli Targa Cod_mod Categoria Cilindrata Cod_comb. cav.Fisc Velocita Posti Imm Select Targa, Cilindrata, Cilindrata – (Select min (Cilindrata) From Veicoli) Differenza From Veicoli 29/12/2018
Esempio Veicoli Modelli Targa Cod_mod Categoria Cilindrata Cod_comb. cav.Fisc Velocita Posti Imm Modelli Cod_Mod Nome_Mod Cod_Fab Cilind_Media Per ciascun veicolo rappresentare la targa e la differenza fra la cilindrata e la cilindrata media del proprio modello Select targa, Cilindrata – (Select cilind_media From Modelli Where Veicoli.cod_mod=Modelli.cod_mod) From Veicoli 29/12/2018
Esercizio Cercare per il componente ‘Anta 100cm’ la differenza rispetto al costo medio dei componenti. Select com_costo – (select AVG(com_costo) From Componenti) From Componenti Where Com_descrizione=‘Anta 100cm’ 29/12/2018
Esercizio Determinare quanto viene a costare ciascun tipo di componente della composizione di ogni articolo, tenendo in considerazione la quantità utilizzata. Select art_cod, com_cod, compart_qta * (Select com_costo From Componenti Where Componenti.com_cod= Compart.com_cod) “Costo Componenti” From Compart 29/12/2018
Subquery Annidate Selezionare targa e velocità dei veicoli che appartengono a Modelli prodotti nella Fabbrica FIAT Veicoli Targa Cod_mod Categoria Cilindrata Cod_comb. cav.Fisc Velocita Posti Imm Modelli Cod_Mod Nome_Mod Cod_Fab Cilind_Media Cod_Fab Nome_Fab Fabbrica Select targa, velocita From Veicoli Where cod_mod in (select cod_mod From Modelli Where cod_fab = (select cod_fab From Fabbrica Where Nome_Fab=‘FIAT’) 29/12/2018
Esempio Veicoli Modelli Targa Cod_mod Categoria Cilindrata Cod_combust. cav.Fisc Velocita Posti Imm Modelli Cod_Mod Nome_Mod Cod_Fab Num_versioni Selezionare i modelli che presentano più versioni del numero minimo di versioni dei veicoli a benzina (Cod_combustibile=’01’). Select * From Modelli Where num_versioni > (Select min (num_versioni) From Modelli Where cod_mod IN (select cod_mod From veicoli Where cod_combust=‘01’) 29/12/2018
Esempio: Nome e reddito dei padri di persone che guadagnano più di 20 milioni SELECT distinct P.Nome, P.Reddito FROM Persone P, Paternita, Persone F WHERE P.Nome = Padre AND Figlio = F.Nome AND F.Reddito > 20 SELECT Nome, Reddito FROM Persone WHERE Nome IN (SELECT Padre FROM Paternita WHERE Figlio =ANY (SELECT Nome FROM Persone WHERE Reddito > 20)) Mediante Join Mediante subquery 29/12/2018
Interrogazioni nidificate, commenti La forma nidificata è “meno dichiarativa”, ma talvolta più leggibile (richiede meno variabili) La forma piana e quella nidificata possono essere combinate Le sottointerrogazioni non possono contenere operatori insiemistici (“l’unione si fa solo al livello esterno”); la limitazione non è significativa 29/12/2018
Interrogazioni nidificate, commenti, 2 La prima versione di SQL prevedeva solo la forma nidificata (o strutturata), con una sola relazione in ogni clausola FROM. Il che è insoddisfacente: la dichiaratività è limitata non si possono includere nella target list attributi di relazioni nei blocchi interni 29/12/2018
Esempio: Nome e reddito dei padri di persone che guadagnano più di 20 milioni, con indicazione del reddito del figlio SELECT distinct P.Nome, P.Reddito, F.Reddito FROM Persone P, Paternita, Persone F WHERE P.Nome = Padre AND Figlio = F.Nome AND F.Reddito > 20 SELECT Nome, Reddito, ???? FROM Persone WHERE Nome in (SELECT Padre FROM Paternita WHERE Figlio = any (SELECT Nome FROM Persone WHERE Reddito > 20)) Mediante Join Mediante Subquery (?) 29/12/2018
Interrogazioni nidificate, commenti, 3 regole di visibilità simili a quelle delle procedure nei linguaggi di programmazione: non è possibile fare riferimenti a variabili definite in blocchi più interni se un nome di variabile è omesso, si assume riferimento alla variabile più “vicina” in un blocco si può fare riferimento a variabili definite in blocchi più esterni 29/12/2018
Confronto su più attributi Il confronto con il risultato di una query nidificata può essere basato su più attributi Trovare tutti gli studenti che hanno un omonimo: SELECT * FROM Studenti S WHERE (Nome, Cognome) IN (SELECT Nome, Cognome FROM Studenti S2 WHERE S2.Matricola <> S.Matricola) 29/12/2018
Visibilità scorretta: SELECT * FROM Impiegato WHERE Dipart in (SELECT Nome FROM Dipartimento D1 WHERE Nome = 'Produzione') OR Dipart in (SELECT Nome FROM Dipartimento D2 WHERE D2.Citta = D1.Citta) D1 non e’ visibile nella seconda query nidificata in quanto le due sottoquery sono allo stesso livello 29/12/2018
Commenti finali sulle query nidificate Query nidificate possono essere “meno dichiarative” in un certo senso ma spesso sono più facilmente interpretabili Suddivisibili in blocchi più semplici da interpretare L’utilizzo di variabili deve rispettare le regole di visibilità Cioè, una variabile può essere usata solo all’interno dello stesso blocco e in un blocco più interno Comunque, query nidificate complesse possono essere di difficile comprensione Soprattutto quando si usano molte variabili comuni tra blocchi diversi 29/12/2018
Esercizio Trovare il nome del negozio che ha ordinato il quantitativo massimo di articoli di uno stesso tipo Select neg_nome From Negozi Where neg_cod in (Select neg_cod From Ordini Where ord_cod =(select ord_cod From Ordart Where ordart_qta= (Select max(ordart_qta) From ordart))) 29/12/2018
Esercizio Dare la descrizione degli articoli che contengono componenti prodotte nei laboratori di Pisa. Select art_descrizione From Articoli Where art_cod IN (Select art_cod From Compart Where com_cod IN(select com_cod From Componenti Where lab_cod in (select lab_cod From laboratori Where lab_citta=‘Pisa’))) 29/12/2018