Interrogazioni nidificate
Una interrogazione nidificata è una interrogazione che contiene un’altra interrogazione. SQL non pone limiti al livello di annidamento ma solitamente più di due annidamenti rendono incomprensibile una query ad un umano (una macchina, invece, non ha problemi di comprensione in questo caso).
E’ possibile nidificare una interrogazione nella clausola where (vedremo un’altra forma di annidamento parlando delle viste).
In particolare una espressione può essere confrontata mediante gli usuali operatori di confronto con una interrogazione.
L’operatore di confronto è seguito dalla parola chiave any oppure all.
Nel primo caso, il predicato è vero se ha successo il confronto (secondo l’operatore usato) tra il valore dell’espressione e almeno uno tra i valori risultato della query. Nel secondo caso, il predicato è vero se ha successo il confronto (secondo l’operatore usato) tra il valore dell’espressione e tutti i valori risultato della query. L’espressione e il risultato dell’interrogazione devono essere compatibili, cioè avere lo stesso numero di attributi e gli attributi devono evere domini compatibili.
Vediamo alcuni esempi. Consideriamo le tabelle attore a autore usate nelle interrogazioni insiemistiche. La seguente interrogazione seleziona tutti gli attori che sono anche autori. Si noti che abbiamo già scritto la stessa query usando l’operatore intersect:
select nome from attore where nome = any (select nome from autore)
Si noti che la query interna è scritta tra parentesi tonde. La seguente interrogazione seleziona tutti gli attori che non sono autori. Si noti che abbiamo già scritto la stessa query usando l’operatore except:
select nome from attore where nome <> all (select nome from autore)
Selezionare tutti gli attori o autori è invece possibile solo usando l’operatore union. Le combinazioni = any e <> all sono molto frequenti e hanno un nome: nel primo caso posso usare la parola chiave in e nel secondo not in. Ad esempio:
select nome from attore where nome not in (select nome from autore)
Se il nome e il cognome di un attore fosse stato specificanto usando due attributi invece che uno soltato, avremmo potuto usare il costruttore di tupla (nome, cognome) in questo modo:
select nome, cognome from attore where (nome, cognome) not in (select nome, cognome from autore)
Il nome del dipendente con lo stipendio massimo può essere estratto nei seguenti due modi:
select nome, stipendio from dipendente where stipendio >= all (select stipendio from dipendente)
select nome, stipendio from dipendente where stipendio = (select max(stipendio) from dipendente)
Si noti che nel secondo caso la parola chiave all o any può essere omessa in quanto la query interna restituisce un solo elemento.
L’interrogazione interna può essere sostituita con un insieme esplicito. L’interrogazione seguente recupera tutti i nomi dei dipendenti in un certo insieme esplicito:
select nome from dipendente where nome in ("Elisa Bottega", "Lorenzo Vignando", "Barbara Altissimo")

Le interrogazioni nidificate viste fin ora possono essere risolte indipendentemente dall’interrogazione che le contiene. Ad esempio, nell’ultima interrogazione scritta, è possibile prima di tutto risolvere la query interna, cioè calcolare il massimo stipendio, e poi elaborare la query esterna confrontando il massimo stipendio con il valore dello stipendio di ogni dipendente. Questa soluzione è più efficiente rispetto a quella che valuta la query interna per ogni tupla della query esterna. Questa soluzione non può però sempre essere seguita. Consideriamo una interrogazione che restituisce gli attori per i quali esiste un altro attore con la medesima data di nascita. Osserviamo innanzitutto che è possibile risolvere l’interrogazione con il seguente join:
select distinct A1.nome from attore A1 join attore A2 on (A1.dataDiNascita = A2.dataDiNascita) and (A1.nome <> A2.nome)
Vediamo ora una soluzione che usa una query nidificata e l’operatore exists. Questo operatore ha come argomento una query interna e restituisce vero se e soltanto se il risultato della query argomento contiene qualche elemento:
select A1.nome from attore A1 where exists (select A2.nome from attore A2 where (A1.dataDiNascita = A2.dataDiNascita) and (A1.nome <> A2.nome))
Questo tipo di query si dicono query nidificate con passaggio di variabili. In particolare, la variabile A1, creata nella query esterna per la prima istanza della tabella attore, viene passata alla query interna che ne fa uso. In tal caso la query interna non può essere valutata indipendentemente da quella esterna in quanto si serve di variabili definite a livello di query esterna. Dunque l’unico modo di risolvere questa query consiste nel valutare la query interna per ogni tupla della query esterna. La visibilità delle variabili in SQL segue la seguente semplice regola: una variabile è visibile nella query che l’ha definita o in una query nidificata in essa (ad un qualsiasi livello).
Vediamo un esempio che usa la negazione dell’operatore exists: gli attori per i quali non esiste un altro attore con la medesima data di nascita:
select A1.nome from attore A1 where not exists (select A2.nome from attore A2 where (A1.dataDiNascita = A2.dataDiNascita) and (A1.nome <> A2.nome))
Una formulazione che non usa le query nidificate è la seguente:
select nome from attore except select A1.nome from attore A1 join attore A2 on (A1.dataDiNascita = A2.dataDiNascita) and (A1.nome <> A2.nome)