back to top

Le subquery in MySQL

A partire dalla versione 4.1 anche MySQL ha introdotto il supporto per le cosiddette subquery, cioè la possibilità di utilizzare delle SELECT all’interno di altre istruzioni. E’ possibile, infatti, creare relazioni tra più tabelle o all’interno della medesima tabella mediante l’utilizzo di subquery all’interno di altre SELECT o di comandi come INSERT o UPDATE, ad esempio.

Iniziamo col dire che le subquery possono essere divise per tipologia a seconda del tipo di risultato che restituiscono:

  • subquery scalari (sono delle SELECT che restituiscono un solo valore)
  • subquery che restituiscono più colonne di un unica riga
  • subquery che restituiscono una sola colonna per una molteplicità di righe
  • subquery correlate
  • subquery nella clausola FROM

A seconda della tipologia, la subquery può essere utilizzata in diversi punti dell’istruzione. Vediamolo nel dettaglio.

Subquery come operando scalare

Una subquery si dice scalare quando restituisce un solo valore. Ad esempio:

SELECT *
FROM libri
WHERE id_autore = (
  SELECT MAX(id) FROM autori
);

Nel nostro esempio la subquery (cioè l’istruzione SELECT utilizzata nella clausola WHERE) restituisce un numero corrispendente all’id più grande della tabella "autori" il quale viene utilizzato dalla SELECT principale per filtrare i risultati della tabella "libri".

Come potete notare la subquery è inserita all’interno di una parentesi tonda: questa è una costante di questo tipo di costruzione.

Le subquery di tipo scalare sono le più semplici e, solitamente, sono utilizzate all’interno della clausola WHERE per verificare che il valore di un campo mediante i consueti operatori di confronto (=, !=, <, >, …) oppure mediante LIKE.

Subquery che restituiscono un unica riga (con più campi)

Questo tipo di subquery, solitamente, è utilizzata per effettuare confronti di valori tra molteplici campi. Vediamo un esempio:

SELECT *
FROM amici
WHERE ROW(nome, cognome) = (
  SELECT nome, cognome FROM parenti WHERE id = 1
);

Nel nostro esempio la selezione sarà realizzata quando le colonne "nome" e "cognome" della tabella "amici" avranno un valore corrispondente a quelli presenti nelle colonne omonime del record con id 1 della tabella "parenti".

Per effettuare questa operazione abbiamo utilizzato il costruttore ROW il quale viene utilizzato, appunto, per effettuare comparazioni con subquery che restituiscono una sola riga con due o più colonne.

Subquery che restituiscono una sola colonna (per molteplici righe)

Se la subquery restituisce una sola colonna per molteplici righe si possono effettuare confronti utilizzando, all’interno della clausola WHERE, alcuni particolari costruttori: ANY (o SOME), IN e ALL.

Per spiegare il funzionamento di questi costruttori facciamo riferimento ad un esempio pratico:

SELECT *
FROM amici
WHERE telefono = ANY(
  SELECT telefono FROM parenti
);

Questa query seleziona dalla tabella "amici" tutti i record in cui il numero di telefono è uguale (=) ad almeno uno (ANY) dei valori estratti dalla tabella "parenti".

E’ opportuno precisare che la nostra query sarebbe stata identica se al posto di ANY avessimo usato SOME in quanto i due costruttori possono essere utilizzati indifferentemente, essendo sinonimi.

Nel nostro esempio abbiamo utilizzato l’operatore di confronto di eguaglianza (=) ma nulla ci vieta di usare uno degli altri operatori (!=, <, >, …). Quando usato con delle subquery la keyword IN (che abbiamo già visto in una precedente lezione) è identica al già visto = ANY.

Vediamo ora il funzionamento del costrutto ALL:

SELECT *
FROM amici
WHERE telefono != ALL(
  SELECT telefono FROM parenti
);

Questa istruzione restituirà la selezione dalla tabella "amici" tutti i record in cui il numero di telefono è diverso (=) ad tutti (ALL) i valori estratti dalla tabella "parenti". Avremmo potuto raggiungere il medesimo risultato utilizzando NOT IN al posto di != ALL.

Subquery correlate

Si dicono correlate le subquery che contengono un riferimento ad una delle tabelle che fanno parte della query esterna:

SELECT *
FROM amici
WHERE nome = ALL(
  SELECT nome
  FROM parenti
  WHERE parenti.citta = amici.citta
);

Con questa query selezioniamo dalla tabella "amici" tutti i record in cui il nome è uguale ad almeno uno di quelli restituiti dalla tabella "parenti" a loro volta selezionati in base ad un’uguaglianza di città tra le due tabelle. E’, appunto, quest’ultimo filtro a definire la subquery come correlata essendo stato utilizzato nella clausola WHERE di quest’ultima un campo della tabella esterna.

Subquery nella clausola FROM

Sino ad ora abbiamo visto delle subquery utilizzati all’interno della clausola WHERE; in realtà, però, le subquery possono essere validamente inserite anche nella clausola FROM. Vediamo un esempio:

SELECT MAX(tbl.quanti)
FROM (
  SELECT COUNT(id) AS quanti, cognome
  FROM amici
  GROUP BY cognome
) AS tbl;

Nel nostro esempio, come potete vedere, la subquery è stata utilizzata nella clausola FROM per creare una sorta di tabella virtuale in cui sono presente tante righe quanti sono i diversi cognomi presenti nella tabella "amici" ed il numero di occorrenze per ciascuno; da questa "tabella", poi, viene estratto il valore massimo mediante la funzione MAX applicata all’alias "quanti".

Pubblicitร 
Massimiliano Bossi
Massimiliano Bossi
Stregato dalla rete sin dai tempi delle BBS e dei modem a 2.400 baud, ho avuto la fortuna di poter trasformare la mia passione in un lavoro (nonostante una Laurea in Giurisprudenza). Adoro scrivere codice e mi occupo quotidianamente di comunicazione, design e nuovi media digitali. Orgogliosamente "nerd" sono il fondatore di MRW.it (per il quale ho scritto centinaia di articoli) e di una nota Web-Agency (dove seguo in prima persona progetti digitali per numerosi clienti sia in Italia che all'estero).

In questa guida...