📁
Forum per Webmaster
SQL

Interrogazioni nidificate

Uno degli aspetti più interessanti del comando Select è costituito dalla possibilità di inserire un comando Select all'interno della struttura di un altro comando Select, ponendo un'interrogazione all'interno di un'altra interrogazione, costruendo cioè interrogazioni nidificate (subquery).
Questa caratteristica spiega la presenza del termine structured nella sigla del linguaggio SQL, per indicare un linguaggio che consente di costruire interrogazioni complesse e ben strutturate.
La condizione scritta dopo Where confronta il valore di un attributo con il risultato di un altro comando Select. Una subquery pu restituire un valore singolo, nessun valore oppure un insieme di valori, ma deve comunque avere una singola colonna o espressione accanto alla sua Select.
Per esempio è possibile ottenere l'elenco con cognome e nome dei dipendenti che hanno lo stipendio base inferiore allo stipendio medio di tutti i dipendenti usando il comando Select espresso nella forma:

SELECT Cognome, Nome
 FROM Personale
 WHERE StipBase
(SELECT AVG (StipBase)
 FROM Personale) ;

Il comando Select nidificato restituisce il valore calcolato del valore medio degli stipendi; questo numero viene usato poi nell'interrogazione principale per il confronto con i valori dell'attributo StipBase nel criterio di selezione delle righe della tabella, scritto dopo Where.
Di seguito viene presentato un altro esempio di subquery con uso del comando Select in una forma che contiene molte delle parole-chiave presentate precedentemente, e che illustra in modo efficace la potenza espressiva del comando Select per indicare con grande concisione un insieme complesso di operazioni.
Supponiamo di voler ricercare i dipendenti, elencando in ordine alfabetico cognome, nome e descrizione della filiale dove lavorano, per i quali lo stipendio risulta uguale al valore massimo tra tutti gli stipendi dei dipendenti con la funzione di Impiegato:

SELECT Cognome, Nome, Descrizione
 FROM Personale, Dipendenza
 WHERE Filiale=CodFil
 AND StipBase ( SELECT MAX(StipBase)
 FROM Personale
 WHERE Funzione='Impiegato')
 ORDER BY Cognome, Nome;

L'interrogazione si ottiene con la congiunzione tra le due tabelle Personale e Dipendenza, realizzata attraverso l'attributo comune del codice filiale; la condizione di selezione sulle righe risultanti confronta lo stipendio di ogni dipendente con il valore ottenuto da una sottointerrogazione che restituisce un numero, ottenuto calcolando con la funzione Max il valore massimo tra tutti i valori di StipBase.
Nella costruzione delle subquery si possono usare alcune clausole che consentono di effettuare interrogazioni più complesse con poche righe di codice SQL.

ANY

Il predicato ANY indica che la subquery può restituire zero, oppure uno, oppure un insieme di valori, e che la condizione di ricerca è vera se il confronto è vero per almeno uno dei valori restituiti. La condizione di ricerca è falsa se la subquery restituisce un insieme vuoto oppure se il confronto è falso per ciascuno dei valori restituiti dalla subquery. Il seguente esempio di interrogazione serve per ottenere le informazioni dei dipendenti che non sono impiegati e che hanno lo stipendio superiore a quello di uno qualsiasi tra gli impiegati:

SELECT Cognome, Nome, Funzione
 FROM Personale
 WHERE Funzione='Impiegato'
 AND StipBase ANY ( SELECT StipBase
 FRON personale
 WHERE Funzione='Impiegato');

ALL

Il predicato ALL indica che la subquery pu restituire zero, oppure uno, oppure un insieme di valori, e che la condizione di ricerca è vera se il confronto è vero per ciascuno dei valori restituiti. La condizione di ricerca è falsa se il confronto è falso per almeno uno tra i valori restituiti dalla subquery.
Sostituendo l'interrogazione precedente con la seguente che contiene All al posto di Any, si possono estrarre tutte le righe dei dipendenti che non sono impiegati e che hanno lo stipendio superiore a quello di tutti gli impiegati.

SELECT Cognome, Nome, Funzione
 FROM personale
 WHERE Funzione='Impiegato'
 AND StipBase ALL ( SELECT StipBase
 FROM personale
 WHERE Funzione='Impiegato');

È logico immaginare che il numero delle righe ottenute con l'interrogazione contenente All sia inferiore al numero di righe restituite dall'interrogazione contenente Any. Le clausole Any e All possono essere tralasciate nelle espressioni di confronto se si è in grado di stabilire che la subquery restituirà sicuramente un solo valore. In questo caso la condizione di ricerca è vera se è vero il confronto tra il valore dell'attributo e il valore restituito dalla subquery.

IN

Il predicato IN serve a controllare se il valore di un attributo è compreso tra quelli restituiti dalla subquery effettuata con la Select nidificata. Il seguente esempio produce l'elenco con cognome e nome dei dipendenti che lavorano nelle filiali che hanno più di 10 dipendenti:

SELECT Cognome, Nome
 FROM Personale
 WHERE Filiale IN (SELECT Filiale
 FRON Personale
 GROUP BY Filiale
 HAVING Count(*) 10)

È possibile utilizzare NOT IN per estrarre solo le righe della tabella principale per le quali nessuna riga della tabella ottenuta con la subquery contiene un valore uguale.

Si osservi che la condizione di ricerca
Where Attributo IN (SELECT ........)

è equivalente a
Where Attributo ANY (SELECT........)

Analogamente la condizione di ricerca
Where Attributo NOT IN (SELECT.........)

è equivalente a
Where Attributo ALL (SELECT..........)

EXISTS

Il predicato EXISTS controlla se vengono restituite righe dall'esecuzione della subquery: la condizione di ricerca è vera se la Select nidificata produce una o più righe come risultato, è falsa se la subquery restituisce un insieme vuoto.
Per esempio se si vuole ottenere l'elenco dei dipendenti con cognome e nome solo se esistono dipendenti di sesto livello, si può usare il comando Select nel seguente formato:

SELECT Cognome, Nome
 FRON Personale
 WHERE EXISTS (SELECT *
 FRON Personale
 WHERE Livello 6) ;

Il predicato Exists è il solo che non confronta un valore con uno o più altri valori. Le colonne utilizzate nella subquery di una clausola Exists sono irrilevanti: quindi per brevità comunemente si utilizza la forma Select * nella subquery. Il predicato Exists può essere negato nella costruzione della condizione di ricerca inserendo la parola NOT prima di Exists.

Argomenti nella stessa categoria