Interrogazioni nidificate SQL
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 Stipendio <
(SELECT AVG (Stipendio)
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 Stipendio 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, Sede
WHERE Filiale = CodFil
AND Stipendio = ( SELECT MAX(Stipendio)
FROM Personale
WHERE Funzione = 'Impiegato')
ORDER BY Cognome, Nome;
L'interrogazione si ottiene con la congiunzione tra le due tabelle Personale e Sede, 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 Stipendio. 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 Stipendio > ANY ( SELECT Stipendio
FROM 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 Stipendio > ALL ( SELECT Stipendio
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 le grado di stabilire che la subquery restituirà sicuramente un solo valore. In questo caso a 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
FROM 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.
Osserviamo 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
FROM Personale
WHERE EXISTS (SELECT *
A FROM 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 puo essere negato nella costruzione della condizione di ricerca inserendo la parola NOT prima di EXISTS.
Pagine correlate:
edutecnica