Tipi di sottoquery SQL È possibile specificare subquery in numerose posizioni: Con le parole chiave IN e NOT IN. Con operatori di confronto. Con le parole chiave ANY, SOME e ALL. Con le parole chiave EXISTS e NOT EXISTS Sottoquery con IN Il risultato di una sottoquery introdotta dalla parola chiave IN (o NOT IN) è un elenco di zero o più valori. I risultati restituiti dalla sottoquery vengono utilizzati dalla query esterna. Nella seguente query vengono trovati i nomi di tutti i prodotti con nome "Ruote" WHERE codicecategoria IN WHERE nome = 'Ruote'); Sottoquery con NOT IN Le sottoquery introdotte dalla parola chiave NOT IN restituiscono un elenco di zero o più valori. La query seguente trova i nomi dei prodotti che non sono biciclette finite. WHERE codicecategoria NOT IN WHERE nome = 'Mountain Bikes' OR nome = 'Road Bikes' OR nome = 'Touring Bikes') Sottoquery con operatori di confronto 1
Le sottoquery possono essere introdotte da uno dei seguenti operatori di confronto =, < >, >, > =, <,! >,! < o < =. In modo analogo alle sottoquery introdotte da IN, le sottoquery introdotte da un operatore di confronto non modificato, ovvero non seguito dalla parola chiave ANY o ALL, devono restituire un solo valore anziché un elenco di valori. Se una sottoquery di questo tipo restituisce più valori, in SQL Server viene visualizzato un messaggio di errore. Per utilizzare una sottoquery introdotta da un operatore di confronto non modificato, è necessario aver acquisito una certa familiarità con i dati e la natura del problema in modo da sapere che la sottoquery restituirà un solo valore. Esempio : Si supponga, ad esempio, che ogni venditore copra una sola zona di vendita e che si desideri trovare i clienti che risiedono nella zona coperta da Mario Rossi. In questo caso è possibile scrivere un'istruzione con una sottoquery introdotta dall'operatore di confronto =. Clienti(codiceFiscale, nome, cognome, telefono, tipo, codicezona, codicevenditore) Venditori(codice, nome, cognome, email, telefono, codicezona) SELECT codicefiscale, nome, cognome FROM Clienti WHERE codicezona = Zona FROM Venditori WHERE nome= Mario AND cognome= Rossi ) NB : posso utilizzare l operatore = perché per ipotesi Mario Rossi copre solo una zona, se i venditori coprono più di una zona (in questo caso il database sarebbe diverso) si doveva utilizzare l operatore IN al posto di = Le sottoquery introdotte da un operatore di confronto non modificato spesso includono funzioni di aggregazione, in quanto tali funzioni restituiscono un solo valore. L'istruzione seguente consente ad esempio di individuare i nomi di tutti i prodotti il cui prezzo di listino è superiore a quello medio. WHERE prezzo > (SELECT AVG (prezzo) FROM prodotti) 2
Poiché le sottoquery introdotte da un operatore di confronto non modificato devono restituire un solo valore, non è possibile includervi clausole GROUP BY o HAVING, a meno che tali clausole non restituiscano un solo valore. La query seguente consente, ad esempio, di individuare i prodotti il cui prezzo è maggiore rispetto al prodotto di prezzo più basso nella categoria 14. WHERE prezzo > (SELECT MIN (prezzo) FROM prodotti GROUP BY codicecategoria HAVING codicecategoria = 14) Operatori di confronto modificati da ANY o ALL Gli operatori di confronto che introducono una sottoquery possono essere modificati tramite le parole chiave ALL o ANY. Le sottoquery introdotte da un operatore di confronto modificato restituiscono un elenco di zero o più valori e possono includere una clausola GROUP BY o HAVING. Tali sottoquery possono essere riformulate con EXISTS (vedi più avanti). Utilizzando l'operatore di confronto > come esempio, >ALL indica maggiore di qualsiasi valore, ovvero maggiore del valore massimo. Ad esempio, >ALL (1, 2, 3) significa maggiore di 3. >ANY significa maggiore di almeno un valore, ovvero, maggiore del valore minimo. >ANY (1, 2, 3) significa maggiore di 1. Una riga di una sottoquery che include >ALL rispetta la condizione specificata nella query esterna se il valore della colonna che introduce la sottoquery è maggiore di tutti i valori dell'elenco restituito dalla sottoquery. In modo analogo, quando si utilizza >ANY, una riga rispetta la condizione specificata nella query esterna se il valore della colonna che introduce la sottoquery è maggiore di almeno uno dei valori dell'elenco restituito dalla sottoquery. La query seguente, in cui viene illustrata una sottoquery introdotta da un operatore di confronto modificato da ANY, trova i prodotti con un prezzo di listino maggiore o uguale al prezzo di listino massimo di tutte le sottocategorie di prodotto. WHERE prezzo >= ANY (SELECT MAX (prezzo) 3
FROM prodotti GROUP BY codicecategoria) Per ogni sottocategoria di prodotto, la query interna trova il prezzo di listino massimo. La query esterna esamina tutti i valori e determina quali prezzi di listino di singoli prodotti sono maggiori o uguali al prezzo di listino massimo delle sottocategorie di prodotto. Se ANY viene sostituito da ALL, la query restituirà unicamente i prodotti con un prezzo di listino maggiore o uguale a tutti i prezzi di listino restituiti dalla query interna. Se la sottoquery non restituisce valori, anche la query non restituisce alcun valore. L'operatore =ANY equivale a IN. WHERE codicecategoria IN WHERE nome = 'Ruote'); Tale query è equivalente a: WHERE codicecategoria = ANY WHERE nome = 'Ruote'); Sottoquery con EXISTS Le sottoquery introdotte dalla parola chiave EXISTS fungono da test di esistenza dei dati. La clausola WHERE della query esterna verifica l'esistenza delle righe restituite dalla sottoquery. La sottoquery non restituisce dati, ma TRUE o FALSE. La query seguente individua i nomi di tutti i prodotti nella categoria Ruote : WHERE codicecategoria EXISTS (SELECT * C INNER JOIN Prodotti P WHERE C.nome = 'Ruote'); 4
Per determinare i risultati di questa query, è necessario considerare di volta in volta se nel nome di ogni prodotto la sottoquery restituisce almeno una riga, in altri termini, se il test di esistenza restituisce TRUE. Sottoquery con NOT EXISTS La parola chiave NOT EXISTS funziona in modo analogo a EXISTS, con la differenza che la clausola WHERE in cui è specificata viene soddisfatta se la sottoquery non restituisce alcuna riga. Per trovare, ad esempio, i nomi dei prodotti che non fanno parte della sottocategoria ruote : WHERE codicecategoria NOT EXISTS (SELECT * C INNER JOIN Prodotti P WHERE C.nome = 'Ruote'); 5
ALTRI ESEMPI 6
7