Le subquery

L’introduzione delle subquery, avvenuta in MySQL con la versione 4.1, è stata probabilmente l’innovazione più attesa da parte degli utilizzatori di questo database. A lungo infatti è stato sottolineato come la mancanza di alcune funzionalità penalizzasse notevolmente MySQL nel confronto con altri RDBMS, e l’assenza delle subquery era sicuramente fra quelle che più si notavano.

Una subquery non è altro che una SELECT all’interno di un’altra istruzione. Le subquery possono essere nidificate anche a profondità notevoli.

Abbiamo già visto che ogni SELECT restituisce logicamente una tabella formata da righe e colonne. Nel caso delle subquery è necessario fare una distinzione: esse infatti possono restituire un valore singolo (scalare), una singola riga, una singola colonna, oppure una normale tabella. Le diverse tipologie di subquery possono trovare posto in diversi punti dell’istruzione.

La subquery come operando scalare.

Il caso più semplice di subquery è quella che restituisce un singolo valore. La si può usare in qualsiasi punto sia possibile utilizzare un valore di colonna. L’uso più frequente lo troviamo come operatore di confronto:

SELECT colonna1 FROM t1
WHERE colonna1 = (SELECT MAX(colonna2) FROM t2);

Questa query estrae i valori di colonna1 nella tabella t1 che sono uguali al valore massimo di colonna2 nella tabella t2.

Subquery che restituiscono colonne.

Quando una subquery restituisce una colonna, può essere usata per fare confronti attraverso gli operatori ANYSOMEIN e ALL:

SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN (SELECT s1 FROM t2);

La prima query significa “seleziona da t1 i valori di s1 che sono maggiori di almeno 1 dei valori di s1 su t2″. La seconda invece seleziona i valori di s1 che sono uguali ad almeno 1 dei valori di s1 su t2. “IN” è sinonimo di “= ANY”. “SOME” è invece equivalente in tutto e per tutto ad “ANY”.

SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);

Il significato qui è “seleziona da t1 i valori di s1 che sono maggiori di tutti i valori di s1 su t2″.
La clausola “NOT IN” equivale a “<> ALL”.

Subquery che restituiscono righe.

Quando una subquery restituisce una singola riga, può essere usata per fare confronti attraverso i costruttori di righe:

SELECT colonna1,colonna2 FROM t1
WHERE (colonna1,colonna2) IN
(SELECT colonna1,colonna2 FROM t2);

Questa query estrae le righe di t1 in cui i valori di colonna1 e colonna2 sono ripetuti in una riga di t2. L’espressione “(colonna1,colonna2)” è, appunto, un costruttore di riga, che poteva essere espresso anche come “ROW(colonna1,colonna2)”.

Subquery correlate.

Le subquery correlate sono quelle che contengono un riferimento ad una tabella che fa parte della query esterna:

SELECT * FROM t1 WHERE colonna1 = ANY
(SELECT colonna1 FROM t2 WHERE t2.colonna2 = t1.colonna2);

In questa subquery, la clausola WHERE contiene un riferimento alla tabella t1, che tuttavia non è nominata nella clausola FROM della subquery stessa: la troviamo infatti nella FROM della query esterna.

Query di questo tipo richiedono che la subquery venga rieseguita ad ogni riga estratta dalla query esterna, e di conseguenza non sono molto performanti. Meglio quindi evitarle quando possibile: spesso infatti una subquery correlata è trasformabile in una join.

Le subquery correlate vengono usate a volte con le clausole EXISTS e NOT EXISTS; la clausola EXISTS è vera quando la subquery restituisce almeno una riga, mentre è falsa nel caso opposto. Ovviamente NOT EXISTS funziona al contrario.

Un esempio:

SELECT DISTINCT tipoNegozio FROM negozi
WHERE EXISTS (SELECT * FROM negozi_citta
WHERE negozi_citta.tipoNegozio = negozi.tipoNegozio);

Ipotizzando che la tabella negozi_citta contenga i tipi di negozio presenti nelle varie città, questa query estrae i tipi di negozio che sono presenti in almeno una città.

Subquery nella FROM.

E’ possibile utilizzare una subquery anche nella clausola FROM, con questa sintassi:

SELECT … FROM (subquery) [AS] nome …

Notate che è obbligatorio assegnare un nome alla subquery, per poterla referenziare nelle altre parti della query. Ad esempio:

SELECT sq.*, t2.c1
FROM (SELECT c1, c2, c3 FROM t1 WHERE c1 > 5) AS sq
LEFT JOIN t2 ON sq.c1 = t2.c1;

In questo caso l’output della subquery viene chiamato “sq” ed il riferimento è usato sia nella SELECT sia nella condizione di join.

Both comments and pings are currently closed.

Comments are closed.