Torna all'elenco degli articoli Articoli
Tempo di lettura: 7 minuti

Che cos'è una query annidata in SQL?

Hai mai desiderato costruire una query con più istruzioni SELECT? Buone notizie! Con le query annidate di SQL puoi fare questo e molto altro.

Se stai imparando il linguaggio SQL (e magari scrivendo qualche query) da un po' di tempo, probabilmente ti sarai imbattuto in casi in cui sembra che sia necessaria un'altra istruzione SELECT all'interno di quella principale. Ti chiederai: "È possibile utilizzare SELECT annidate in SQL?". Sì, è possibile! In questo articolo descriverò le query annidate (alias SELECT annidate) e come utilizzarle in modo efficiente.

Se vuoi esercitarti con SQL, dai un'occhiata al nostro percorso Pratica su SQL che offre diversi corsi interattivi di SQL con esercizi che riguardano le istruzioni SELECT annidate e altre funzioni SQL più complesse.

Che cos'è una SELECT annidata?

Una SELECT annidata è una query all'interno di una query, cioè una struttura che prevede un'istruzione SELECT all'interno della SELECT principale. Per rendere più chiaro il concetto, analizziamo insieme un esempio.

In questo articolo lavoreremo con i dati di una scuola superiore statunitense immaginaria. Il database comprende tre tabelle: students, teachers e classes. Puoi vederle qui sotto:

Students

idnameclass_idGPA
1Jack Black33.45
2Daniel White13.15
3Kathrine Star13.85
4Helen Bright23.10
5Steve May22.40

Teachers

idnamesubjectclass_idmonthly_salary
1Elisabeth GreyHistory32,500
2Robert SunLiterature[NULL]2,000
3John ChurchillEnglish12,350
4Sara ParkerMath23,000

Classes

idgradeteacher_idnumber_of_students
110321
211425
312128

Supponiamo di voler trovare tutti gli studenti che hanno una valutazione GPA superiore alla media. Tuttavia, non conosci il punteggio medio delle valutazioni. Naturalmente, puoi usare una query per scoprirlo:

SELECT AVG(GPA)
FROM students;

Otterrai un numero (3,19) che potrai utilizzare per risolvere il problema iniziale: mostrare tutte le informazioni relative agli studenti con una valutazione superiore a questa:

SELECT *
FROM students
WHERE GPA > 3.19;

Ma è possibile risolvere questo compito in un solo passaggio? Sì, grazie a una query annidata. Ecco che aspetto avrebbe:

SELECT *
FROM students
WHERE GPA > (
	SELECT AVG(GPA)
	FROM students);

La nostra sottoquery restituisce un singolo valore (cioè una tabella con una singola colonna e una singola riga). Questo è importante per il funzionamento dell'operatore di confronto. Con il punteggio medio di GPA restituito dalla query interna, quella esterna può selezionare gli studenti che soddisfano la nostra condizione filtro (cioè un punteggio di GPA superiore alla media).

Ed ecco il risultato:

idnameclass_idGPA
1Jack Black33.45
3Kathrine Star13.85

Il termine corretto per questa istruzione SELECT annidata è subquery. Ci sono molti scenari diversi in cui le sottoquery SQL sono molto utili.

Altri esempi di query SQL annidate

Innanzitutto, è possibile inserire una SELECT annidata all'interno della clausola WHERE con gli operatori di confronto o gli operatori IN, NOT IN, ANY, o ALL. Il secondo gruppo di operatori si usa quando la subquery restituisce un elenco di valori (anziché un singolo valore, come nell'esempio precedente):

  • L'operatore IN controlla se un determinato valore è presente nella tabella restituita dalla subquery.
  • L'operatore NOT IN filtra le righe corrispondenti ai valori non presenti nella tabella restituita dalla subquery.
  • L'operatore ANY viene utilizzato con gli operatori di confronto per valutare se uno qualsiasi dei valori restituiti dalla subquery soddisfa la condizione.
  • Anche l'operatore ALL viene utilizzato con gli operatori di confronto per valutare se tutti i valori restituiti dalla subquery soddisfano la condizione.

Vediamo come funziona l'operatore IN. In questo esempio, calcoleremo il numero medio di studenti nelle classi in cui il professore insegna Storia o Inglese:

SELECT AVG(number_of_students)
FROM classes
WHERE teacher_id IN (
	SELECT id
	FROM teachers
	WHERE subject = 'English' OR subject = 'History');

In questo caso, utilizziamo una subquery per selezionare solo gli ID degli insegnanti che corrispondono alle materie di Storia o Inglese. Nota che la subquery restituisce un elenco di valori, ossia una tabella con una colonna (id) e più righe che soddisfano la condizione della query interna.

Quindi, nella nostra query esterna, calcoliamo il numero medio di studenti solo per le classi che soddisfano la condizione precedente. Per ogni teacher_id, l'operatore IN controlla se quel codice identificativo è presente nella tabella restituita dalla query interna; questo assicura che solo le classi corrispondenti a questi insegnanti siano considerate nel calcolo.

Per ulteriori esempi di utilizzo degli operatori IN, NOT IN, ANY o ALL, consulta la guida alle subquery SQL.

Più subquery in un'unica istruzione

Sei pronto per esempi più impegnativi? È possibile avere più SELECT annidate in un'unica istruzione.

Supponiamo di voler mostrare tutte le informazioni sugli studenti della classe con il maggior numero di studenti. Per rispondere a questa domanda, è necessario trovare la classe con il numero massimo di studenti e definirla. Infine, è necessario mostrare le informazioni sugli studenti di quella classe.

Per rispondere a questa domanda è possibile utilizzare una sottoquery all'interno di un'altra:

SELECT *
FROM students
WHERE class_id = (
	SELECT id
	FROM classes
	WHERE number_of_students = (
		SELECT MAX(number_of_students)
		FROM classes));

Comodo, vero?

Utilizzo delle subquery al di fuori di WHERE

Inoltre, le subquery non sono limitate all'uso nella clausola WHERE. Per esempio, è possibile utilizzare una query annidata anche nella clausola FROM. Nel prossimo esempio, la nostra subquery non restituirà un singolo valore, ma una tabella.

Scopriamo a quale materia corrisponde il più alto stipendio medio degli insegnanti. Per prima cosa è necessario calcolare lo stipendio medio per materia, quindi utilizziamo questa tabella per trovare lo stipendio medio massimo:

SELECT subject, MAX(salary_by_subject.avg_salary) AS max_salary
FROM (
	SELECT subject, AVG(monthly_salary) AS avg_salary
	FROM teachers
	GROUP BY subject) salary_by_subject;

Nota che la query interna restituirà una tabella con più righe e colonne. Per essere più precisi, la tabella avrà due colonne, subject e avg_salary, per mostrare lo stipendio medio degli insegnanti in base alla loro materia principale. Il numero di righe corrisponderà al numero di materie uniche insegnate nella scuola (come specificato nella tabella teachers). È inoltre necessario specificare un nome alternativo (alias) per questa tabella: salary_by_subject.

Quindi, la query esterna calcola semplicemente il salario medio massimo in base alla tabella salary_by_subject e restituisce questo valore, insieme al nome della materia corrispondente:

subjectmax_salary
Math3,000

Come puoi vedere, gli insegnanti di Matematica della scuola del nostro esempio hanno lo stipendio medio mensile più alto (3000 dollari).

Per alcune attività, potrebbe essere necessario che la query interna utilizzi le informazioni di quella esterna. Quando due query sono collegate in questo modo, si parla di sottoquery correlate. Si tratta di un argomento più avanzato che viene spiegato approfonditamente nella nostra guida per principianti alle subquery correlate e in questo tutorial pratico sulla scrittura di subquery correlate.

Ulteriori suggerimenti sull'uso delle SELECT annidate

Le subquery SQL sono uno strumento potente. Consentono di eseguire operazioni in modo più efficiente grazie a una sola query invece di impiegarne diverse.

Quando si utilizzano le query annidate, è bene tenere a mente le seguenti considerazioni:

  • Le subquery possono restituire singoli valori o tabelle (con una o più righe e colonne).
  • È possibile includere una subquery:
    • Nella clausola WHERE, per filtrare i dati.
    • Nella clausola FROM, per specificare una nuova tabella.
    • Nella clausola SELECT, per specificare una determinata colonna.
    • Nella clausola HAVING, come selettore di gruppo.
  • Le subquery devono sempre essere racchiuse tra parentesi ().
  • I diversi sistemi di gestione dei database hanno alcune limitazioni sul numero di livelli di subquery (per esempio, fino a 32 livelli in SQL Server). Tuttavia, nella pratica, raramente dovrai ricorrere a più di 2-3 livelli di query annidate.
  • Le subquery sono spesso inefficienti dal punto di vista computazionale. Pertanto, consiglio di evitare le query annidate quando sono disponibili altre opzioni (per esempio, le istruzioni JOIN).

È ora di fare pratica con le subquery SQL!

Ora che hai imparato molto sulle query annidate in SQL, probabilmente non vedi l'ora di iniziare a metterle in pratica! Per fortuna, abbiamo messo a tua disposizione un sacco di esercizi interattivi per permetterti di prendere familiarità con le diverse subquery SQL.

Prima di tutto, il nostro corso Nozioni di base di SQL ha un'ampia sezione sulle subquery. Assicurati di darci un'occhiata!

Se vuoi acquisire totale padronanza delle query annidate in SQL, ti consiglio di completare il nostro percorso Pratica su SQL. Questo percorso contiene corsi interattivi di SQL con esercizi pratici per prendere familiarità con le subquery e altre costruzioni impegnative di SQL.

Le subquery ti renderanno sicuramente un utente SQL molto più capace. Buon apprendimento!