CodeGym /Corsi /SQL SELF /Esempi di query annidate complesse: combinazione di EXIST...

Esempi di query annidate complesse: combinazione di EXISTS, IN, HAVING

SQL SELF
Livello 14 , Lezione 3
Disponibile

Congratulazioni, siamo arrivati al punto in cui le cose diventano davvero interessanti! Oggi vediamo come combinare diversi tipi di subquery per risolvere problemi complessi. EXISTS, IN, HAVING — questo trio ti farà sentire un vero mago dei database. Prenderemo dati da una tabella, li filtreremo usando dati da un'altra, li raggrupperemo e poi filtreremo i gruppi. E come bonus — vediamo anche qualche trucco per rendere le query più efficienti.

Iniziamo con la definizione di un problema generale che risolveremo passo dopo passo durante la lezione.

Definizione del problema

Supponiamo di avere un database universitario con tre tabelle:

Tabella students

id name group_id
1 Otto 101
2 Maria 101
3 Alex 102
4 Anna 103

Tabella courses

id name
1 Matematica
2 Programmazione
3 Filosofia

Tabella enrollments

student_id course_id grade
1 1 90
1 2 NULL
2 1 85
3 3 70

Dobbiamo selezionare tutti gli studenti che:

  1. Sono iscritti almeno a un corso EXISTS.
  2. Non hanno un voto almeno in uno dei corsi a cui sono iscritti IN.
  3. Appartengono a gruppi in cui la media dei voti è superiore a 80 HAVING.

Soluzione usando EXISTS e IN

Passo 1: Controllo degli studenti iscritti (EXISTS). Partiamo dalla condizione più semplice. Dobbiamo capire chi tra gli studenti è iscritto almeno a un corso. Per questo usiamo EXISTS.

SELECT name
FROM students s
WHERE EXISTS (
  SELECT 1
  FROM enrollments e
  WHERE e.student_id = s.id
);
  1. La query esterna seleziona i nomi dalla tabella students.
  2. Nella subquery controlliamo se ci sono record nella tabella enrollments che corrispondono allo studente della query esterna (WHERE e.student_id = s.id).
  3. SELECT 1 serve solo per dire che ci interessa la presenza di record, non il loro contenuto.

Risultato:

name
Otto
Maria
Alex

Ora sappiamo chi tra gli studenti è iscritto ai corsi. Ma vogliamo di più. Vogliamo filtrarli per assenza di voto.

Passo 2: Controllo dell'assenza di voto (IN + NULL). Ora aggiungiamo il filtro: ci servono solo gli studenti che hanno almeno un corso senza voto. Qui ci aiutano IN e la conoscenza di come funziona NULL.

SELECT name
FROM students s
WHERE id IN (
  SELECT e.student_id
  FROM enrollments e
  WHERE e.grade IS NULL
);
  1. Nella query esterna selezioniamo i nomi degli studenti.
  2. La subquery crea una lista di student_id dalla tabella enrollments dove grade IS NULL.

Risultato:

name
Otto

Quindi, Otto è l'unico studente che ha un corso senza voto. Che dramma! Ma non abbiamo ancora finito: dobbiamo considerare solo i gruppi con media superiore a 80.

Soluzione usando HAVING

Passo 3: Raggruppamento e filtro con HAVING.

Ora è il momento di mettere tutto insieme. Dobbiamo:

  1. Calcolare la media dei voti per ogni gruppo.
  2. Filtrare i gruppi con media superiore a 80.
  3. Mostrare gli studenti di questi gruppi, considerando le condizioni precedenti.
SELECT name
FROM students s
WHERE s.group_id IN (
  SELECT group_id
  FROM students
  JOIN enrollments ON students.id = enrollments.student_id
  WHERE grade IS NOT NULL
  GROUP BY group_id
  HAVING AVG(grade) > 80
)
AND id IN (
  SELECT e.student_id
  FROM enrollments e
  WHERE e.grade IS NULL
);
  1. La query esterna seleziona i nomi degli studenti che rispettano tutte le condizioni.
  2. La prima subquery in WHERE restituisce la lista di group_id per i gruppi con media superiore a 80.
    • Facciamo un join tra students e enrollments per ottenere i voti.
    • Filtriamo solo i record dove grade IS NOT NULL.
    • Raggruppiamo per group_id.
    • Usiamo HAVING per filtrare i gruppi.
  3. La seconda subquery in WHERE controlla che lo studente abbia almeno un corso senza voto.
  4. Le due condizioni sono unite con AND.

Risultato:

name
Otto

Quindi abbiamo scoperto che Otto non è solo l'unico studente senza voto, ma appartiene anche a un gruppo che va alla grande.

Confronto tra approcci: EXISTS vs IN

EXISTS funziona meglio quando vuoi controllare velocemente la presenza di record. È efficiente perché si ferma appena trova il primo record. Questo è importante soprattutto con tabelle grandi.

Allo stesso tempo IN è utile quando ti interessa il contenuto dei dati. Per esempio, se vuoi una lista di identificatori (id) per filtri successivi. Ma occhio: IN può diventare lento se la subquery restituisce tanti valori.

Quando usare HAVING

Per dati aggregati, quando devi filtrare in base ai risultati, HAVING è la scelta migliore. Ma se puoi spostare la condizione in WHERE (tipo un filtro su una colonna), la query sarà più semplice e veloce.

Esempio completo

Per fissare meglio il concetto, vediamo un altro esempio: selezionare i gruppi dove almeno uno studente ha un voto sotto 75, ma che non sono iscritti al corso "Filosofia".

Ricordiamo le nostre tabelle:

Tabella students

id name group_id
1 Otto 101
2 Maria 101
3 Alex 102
4 Anna 103

Tabella courses

id name
1 Matematica
2 Programmazione
3 Filosofia

Tabella enrollments

student_id course_id grade
1 1 90
1 2 NULL
2 1 85
3 3 70
SELECT DISTINCT group_id
FROM students s
WHERE group_id IN (
  SELECT s.group_id
  FROM students s
  JOIN enrollments e ON s.id = e.student_id
  WHERE e.grade < 75
)
AND group_id NOT IN (
  SELECT s.group_id                                 -- subquery di primo livello
  FROM students s
  JOIN enrollments e ON s.id = e.student_id
  WHERE e.course_id = (
    SELECT id FROM courses WHERE name = 'Filosofia' -- subquery di secondo livello :P
  )
);
  1. La prima subquery seleziona i gruppi dove c'è almeno uno studente con voto sotto 75.
  2. La seconda subquery esclude i gruppi collegati al corso "Filosofia".
  3. Combiniamo le condizioni con IN e NOT IN per ottenere il risultato finale.

Risultato:

group_id
101

Quanto è utile tutto questo?

Nella vita reale questi approcci ti salvano quando devi analizzare relazioni complesse tra dati. Per esempio:

  • Nell'analisi per individuare gruppi "speciali" di clienti (VIP, problematici ecc.).
  • Nello sviluppo di sistemi di raccomandazione, dove filtri l'utente su tanti criteri.
  • Ai colloqui, quando ti chiedono di ottimizzare una query SQL complessa.

Allenati! È la tua strada verso la maestria.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION