In questo articolo vedremo come scrivere una JOIN con il linguaggio SQL per collegare i dati presenti in più tabelle di un database relazionale. Utilizzare correttamente l’operatore di JOIN in SQL è un aspetto importantissimo che chiunque si avvicini al mondo delle query deve imparare a padroneggiare.
Join SQL: la sintassi
Nella clausola SELECT possiamo scrivere più colonne separandole con una virgola. Di conseguenza, se abbiamo bisogno nella stessa query di più tabelle, ad esempio Clienti e Conti), un tentativo naturale sarebbe quello di scriverle nella FROM e separarle con una virgola (SPOILER: NON FATELO!)
SELECT * FROM Clienti, Conti
In questo modo però otterremmo tutte le combinazioni possibili tra le righe delle due tabelle. Se ad esempio la tabella Clienti ha diecimila righe e la tabella Conti ne ha mille, la query precedente restituirà 10000*1000 = 10000000 righe! Sì, avete letto bene, dieci milioni. Avete visto come è semplice intasare un database di produzione?
Tuttavia la maggior parte di queste combinazioni saranno errate dal punto di vista logico. Ci aspettiamo infatti che all’interno delle due tabella Conti e Clienti sia presente una colonna comune IdCliente: di tutte le combinazioni precedenti vogliamo lasciare solamente quelle dove i dati delle tue colonne combaciano. Arriviamo dunque a questa query:
SELECT * FROM Clienti, Conti WHERE Clienti.IdCliente = Conti.IdCliente;
Per quanto corretta e ancora utilizzata da molti programmatori, questa modalità di combinare i dati tra tabelle è stata superata da una sintassi più moderna, che presenta numerosi vantaggi in termini di leggibilità e manutenibilità. Essa fa uso delle istruzioni JOIN e ON e ci permette di scrivere una query equivalente a quella precedente in questo modo:
SELECT * FROM Clienti INNER JOIN Conti ON Clienti.IdCliente = Conti.IdCliente
In questa query abbiamo utilizzato una INNER JOIN, ma vedremo che non sarà l’unica tipologia possibile.
Differenze tra le diverse tipologie di JOIN
Oltre a INNER e LEFT, esistono ulteriori tipologie di Join. Analizziamo quattro query in cui l’unica differenza è “l’aggettivo” che precede l’operatore JOIN:
SELECT * FROM Fatture INNER/LEFT/RIGHT/FULL JOIN Fornitori ON Fatture.IdFornitore = Fornitori.IdFornitore;
- Con la Inner Join mostreremo solo le combinazioni valide, equivalentemente alla sintassi con la virgola e la condizione WHERE.
- Con la Left Join mostreremo mostra le combinazioni valide e le fatture senza fornitori associati.
- Con la Right Join mostra le combinazioni valide e in più fornitori senza fatture associate.
- Con la Full Join mostra le combinazioni valide, più le fatture senza fornitori associati, più i fornitori senza fatture associate.
Un’ultima tipologia di JOIN è la Cross Join che non richiede l’operatore ON. Essa mostra tutte le possibili combinazioni ed è dunque equivalente a separare le due tabella con la virgola nella FROM, senza inserire nessuna condizione nella WHERE.
Curiosità: sapevi che su MySQL non esiste la full join? Puoi approfondire in questo link https://www.yimp.it/full-join-mysql/ come arrivare a un risultato analogo.
Alleggeriamo la sintassi
Nella SELECT possiamo utilizzare l’AS per rinominare la colonna nell’output della query. Analogamente nella FROM possiamo usare l’AS per rinominare le tabelle all’interno della query e alleggerire così la sintassi. Ad esempio nel caso precedente potremmo scrivere
SELECT Fa.*, Fo.Denominazione FROM Fatture AS Fa INNER JOIN Fornitori AS Fo ON Fa.IdFornitore = Fo.IdFornitore;
Vi consiglio di utilizzare una rinomina breve e che faccia riferimento alla tabella originale. In teoria è obbligatorio far precedere il nome della colonna dal riferimento alla tabella solo nel caso in cui la colonna sia ripetuta identicamente in più di una tabella. Tuttavia il mio consiglio è di specificare la tabella in qualsiasi caso. Con poco sforzo in più, otterrete una query molto più leggibile e facile da rianalizzare in futuro. Puoi leggere qui altre buone pratiche di sviluppo SQL.
Perché scegliere la sintassi con la JOIN esplicita
Ti riporto alcuni motivi per i quali preferisco esplicitare l’operatore JOIN e usare la condizione ON, invece di usare la virgola nella FROM e aggiungere una condizione nella WHERE
- leggibilità: ricordiamo che l’SQL è un linguaggio english-Like, la query deve riflettere il modo di esprimersi nel nostro linguaggio naturale. Negli esempi di prima l’obiettivo è collegare le tabelle utilizzando la colonna in comune IdCliente. Per far questo la sintassi con la JOIN esplicita è sicuramente più chiara, basta pensare alla traduzione in italiano della parola JOIN. In questo modo teniamo ben distinta la porzione di codice che esplica il collegamento tra le tabelle, da quella dove impostiamo altri filtri sui dati (come ad esempio su un’ulteriore colonna come la Regione di Residenza). Senza la JOIN tale distinzione risulta più difficile. Pensate a cosa succede quando la query è più complessa e sono presenti numerosissime join e svariati filtri;
- manutenibilità: supponiamo di dover trasformare l’INNER JOIN in una LEFT JOIN. Se abbiamo già esplicitato la JOIN ci basterà modificare una parola! Altrimenti su molti database dovremo riscrivere completamente la query;
- facilità di scrittura: supponiamo di voler eliminare temporaneamente la JOIN. Se ho utilizzato la WHERE per scrivere la condizione di collegamento l’operazione risulterà sicuramente più complessa e comprende il rischio di commentare per errore anche un filtro su un’altra colonna.
Gestire la presenza di null nelle Join in SQL
La presenza di NULL complica spesso la scrittura di una query soprattutto quando la condizione di JOIN coinvolge più colonne. Supponiamo ad esempio che la tabella dei clienti e dei conti devono essere collegate secondo questa specifica: devono avere lo stesso codice_conto e, se presente, lo stesso codice_valuta. Chi lavora in ambito banking avrà sicuramente riconosciuto questa specifica collegata alla presenza di conti in più valute.
Occorre fare molta attenzione perché la seguente query, all’apparenza corretta, esclude tutti quei conti che hanno NULL nella colonna codice_valuta
SELECT * FROM DimConto AS c INNER JOIN SnapshotConto AS s ON c.codice_conto = s.codice_conto AND c.codice_valuta = s.codice_valuta;
Per risolvere questa fastidiosa situazione, vi lascio un link a un fantastico articolo di Itzik Ben Gan legato alla gestione del NULL. Vi riporto la soluzione più “elegante”:
SELECT c.*, s.* FROM DimConto AS c INNER JOIN SnapshotConto AS s ON EXISTS(SELECT c.codice_conto, c.codice_valuta INTERSECT SELECT s.codice_conto, s.codice_valuta);
Conclusioni sull’utilizzo di Join
La Join è una delle operazioni più importanti del linguaggio SQL in quanto permette di combinare i dati appartenenti a più tabelle. Nell’articolo abbiamo visto i vantaggi di esplicitare direttamente il costrutto il Join con la clausola ON, invece di usare il carattere virgola nella FROM e un’ulteriore condizione WHERE. Occorre inoltre far attenzione a utilizzare correttamente le varie tipologie di Join (inner, left, right, full e cross) e a gestire con attenzione la presenza di null. Per approfondire ulteriormente questi temi puoi visitare la pagina del mio video-corso sul linguaggio SQL https://www.yimp.it/corso-sql-academy/
Altre risorse utili possono essere:
- Il mio articolo sulla Group by
- Il mio articolo sulla Where
- Il mio corso in diretta streaming sul linguaggio SQL