Andiamo ancora più a fondo nella tana del Bianconiglio: vediamo come usare le subquery nella clausola FROM. È uno dei metodi più usati dagli sviluppatori SQL, perché ti permette di creare potenti tabelle temporanee direttamente "sul momento" e riutilizzarle come se fossero vere tabelle nel database.
Immagina che devi fare un report che richiede calcoli, raggruppamenti o filtri sui dati, ma non vuoi creare tabelle temporanee aggiuntive sul server. Che si fa? Ecco che arrivano in soccorso le subquery in FROM. Ti permettono di:
- Unire o aggregare dati temporaneamente prima della query principale.
- Creare set di dati strutturati "al volo".
- Ridurre il numero di operazioni, chiedendo al database di salvare il minimo indispensabile di dati intermedi.
Le subquery in FROM funzionano come mini-tabelle che puoi usare nella query principale. È un po' come costruire con i mattoncini: veloce, flessibile e senza troppi sbattimenti :)
Basi delle subquery in FROM
Nelle subquery in FROM usiamo una subquery per creare una tabella temporanea (o sotto-tabella) che diventa parte della query generale. Devi fare tre passi chiave:
- Scrivi la subquery nella clausola
FROMtra parentesi tonde. - Dai un alias (pseudonimo) alla subquery.
- Usa questo alias come se fosse una vera tabella.
Sintassi
SELECT colonne
FROM (
SELECT colonne
FROM tabella
WHERE condizione
) AS alias
WHERE condizione_esterna;
Sembra complicato? Vediamo subito degli esempi.
Esempio: Studenti e media voti
Supponiamo di avere due tabelle:
students (dati sugli studenti — nome e ID):
| student_id | student_name |
|---|---|
| 1 | Alex |
| 2 | Anna |
| 3 | Dan |
grades (dati sui voti degli studenti):
| grade_id | student_id | grade |
|---|---|---|
| 1 | 1 | 80 |
| 2 | 1 | 85 |
| 3 | 2 | 90 |
| 4 | 3 | 70 |
| 5 | 3 | 75 |
Ora il compito: ottenere la lista degli studenti e la loro media voti.
Possiamo partire da una semplice subquery che calcola la media dei voti di ogni studente, e poi usarla nella query principale.
SELECT s.student_name, g.avg_grade
FROM (
SELECT student_id, AVG(grade) AS avg_grade
FROM grades
GROUP BY student_id
) AS g
JOIN students AS s ON s.student_id = g.student_id;
Risultato:
| student_name | avg_grade |
|---|---|
| Alex | 82.5 |
| Anna | 90.0 |
| Dan | 72.5 |
Tabelle temporanee "al volo"
Le subquery in FROM sono super utili quando devi fare più di un livello di elaborazione dati. Per esempio, se vuoi non solo la media, ma anche il voto massimo per ogni studente — tutto in una sola query.
SELECT g.student_id, g.avg_grade, g.max_grade
FROM (
SELECT student_id,
AVG(grade) AS avg_grade,
MAX(grade) AS max_grade
FROM grades
GROUP BY student_id
) AS g;
Risultato:
| student_id | avg_grade | max_grade |
|---|---|---|
| 1 | 82.5 | 85 |
| 2 | 90 | 90 |
| 3 | 72.5 | 75 |
Nota che funziona proprio come una tabella temporanea vera e propria con le sue colonne: avg_grade e max_grade.
Quando conviene usare le subquery in FROM?
Per dati aggregati. Se vuoi prima fare dei calcoli (tipo media, somme o massimi) e poi unire i risultati con altre tabelle.
Per filtrare dati. Quando vuoi filtrare i dati prima di unirli alla tabella principale.
Per semplificare query complesse. Dividere i problemi complicati in step aiuta a non perdersi.
Esempio: Report studenti con due livelli di elaborazione
Immagina che vogliamo trovare gli studenti con media voti sopra 80. Partiamo da una subquery che calcola le medie, poi la usiamo nel filtro.
SELECT s.student_name, g.avg_grade
FROM students AS s
JOIN (
SELECT student_id, AVG(grade) AS avg_grade
FROM grades
GROUP BY student_id
) AS g ON s.student_id = g.student_id
WHERE g.avg_grade > 80;
Risultato:
| student_name | avg_grade |
|---|---|
| Alex | 82.5 |
| Anna | 90.0 |
Consigli e particolarità d'uso
Alias obbligatorio. Dai sempre un alias alla subquery (tipo AS g), altrimenti PostgreSQL non capisce come riferirsi a questa "tabella temporanea".
Ottimizzazione. Le subquery in FROM possono essere più lente dei join tra tabelle (JOIN), soprattutto se filtri i dati dentro la subquery.
Indicizzazione. Assicurati che i campi usati per i join, gli indici e i filtri siano ottimizzati — fa una grossa differenza sulle performance.
Esempio query complessa: corsi e numero studenti
Ora facciamo un esercizio più tosto. Immagina di avere questa tabella:
courses (lista dei corsi):
| course_id | course_name |
|---|---|
| 1 | SQL Basics |
| 2 | Python Basics |
E enrollments (iscrizioni degli studenti ai corsi):
| student_id | course_id |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
Ora vogliamo sapere quanti studenti sono iscritti a ogni corso.
SELECT c.course_name, e.students_count
FROM courses AS c
JOIN (
SELECT course_id, COUNT(student_id) AS students_count
FROM enrollments
GROUP BY course_id
) AS e ON c.course_id = e.course_id;
Risultato:
| course_name | students_count |
|---|---|
| SQL Basics | 2 |
| Python Basics | 1 |
Spero che la lezione ti sia piaciuta... ma la prossima sarà ancora più interessante :)
GO TO FULL VERSION