Finora, le nostre query hanno avuto accesso ad una sola tabella alla volta. Le query possono accedere a più tabelle contemporaneamente, o accedere alla stessa tabella in modo tale che più righe della tabella siano processate allo stesso tempo. Una query che accede a più righe della stessa tabella o di tabelle diverse in una sola volta è chiamata join query. Come esempio, diciamo che si desidera elencare tutti i record del tempo insieme alla posizione della città associata. Per farlo, abbiamo bisogno di confrontare la colonna città di ogni riga della tabella meteo con la colonna nome di tutte le righe della tabella città, e selezionare le coppie di righe in cui questi valori corrispondono.
Nota: Questo è solo un modello concettuale. Il join è di solito eseguito in modo più efficiente che confrontando effettivamente ogni possibile coppia di righe, ma questo è invisibile all’utente.
Questo verrebbe realizzato dalla seguente query:
SELECT * FROM weather, cities WHERE city = name;
city | temp_lo | temp_hi | prcp | date | name | location---------------+---------+---------+------+------------+---------------+----------- San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53) San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53)(2 rows)
Osserva due cose sull’insieme dei risultati:
-
Non c’è nessuna riga di risultato per la città di Hayward. Questo perché non c’è nessuna voce corrispondente nella tabella
cities
per Hayward, quindi il join ignora le righe non corrispondenti nella tabella meteo. Vedremo a breve come questo può essere risolto. -
Ci sono due colonne che contengono il nome della città. Questo è corretto perché le liste di colonne della tabella
weather
e della tabellacities
sono concatenate. In pratica, però, questo non è desiderabile, quindi probabilmente vorrete elencare le colonne di output esplicitamente piuttosto che usare *:SELECT city, temp_lo, temp_hi, prcp, date, location FROM weather, cities WHERE city = name;
Esercizio: Tentate di scoprire la semantica di questa query quando la clausola WHERE viene omessa.
Siccome le colonne hanno tutte nomi diversi, il parser ha scoperto automaticamente a quale tabella appartengono, ma è buona norma qualificare completamente i nomi delle colonne nelle query di join:
SELECT weather.city, weather.temp_lo, weather.temp_hi, weather.prcp, weather.date, cities.location FROM weather, cities WHERE cities.name = weather.city;
Le join queries del tipo visto finora possono essere scritte anche in questa forma alternativa:
SELECT * FROM weather INNER JOIN cities ON (weather.city = cities.name);
Questa sintassi non è così comunemente usata come quella sopra, ma la mostriamo qui per aiutarvi a capire gli argomenti seguenti.
Ora capiremo come far rientrare i record di Hayward. Quello che vogliamo che la query faccia è scansionare la tabella weather
e per ogni riga trovare la riga corrispondente cities
. Se non viene trovata nessuna riga corrispondente, vogliamo che alcuni “valori vuoti” siano sostituiti per le colonne della tabella cities
. Questo tipo di query è chiamato outer join. Il comando assomiglia a questo:
SELECT * FROM weather LEFT OUTER JOIN cities ON (weather.city = cities.name); city | temp_lo | temp_hi | prcp | date | name | location---------------+---------+---------+------+------------+---------------+----------- Hayward | 37 | 54 | | 1994-11-29 | | San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53) San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53)(3 rows)
Questa query è chiamata una join esterna sinistra perché la tabella menzionata a sinistra dell’operatore di join avrà ciascuna delle sue righe nell’output almeno una volta, mentre la tabella a destra avrà in output solo quelle righe che corrispondono a qualche riga della tabella di sinistra. Quando viene emessa una riga della tabella di sinistra per la quale non c’è corrispondenza nella tabella di destra, vengono sostituiti valori vuoti (nulli) per le colonne della tabella di destra.
Esercizio: Ci sono anche le giunzioni esterne a destra e le giunzioni esterne complete. Provate a scoprire cosa fanno.
Possiamo anche unire una tabella contro se stessa. Questo è chiamato self join. Come esempio, supponiamo di voler trovare tutti i record del tempo che sono nell’intervallo di temperatura di altri record del tempo. Quindi abbiamo bisogno di confrontare le colonne temp_lo e temp_hi di ogni riga weather
con le colonne temp_lo e temp_hi di tutte le altre righe weather
. Possiamo farlo con la seguente query:
SELECT W1.city, W1.temp_lo AS low, W1.temp_hi AS high, W2.city, W2.temp_lo AS low, W2.temp_hi AS high FROM weather W1, weather W2 WHERE W1.temp_lo < W2.temp_lo AND W1.temp_hi > W2.temp_hi; city | low | high | city | low | high---------------+-----+------+---------------+-----+------ San Francisco | 43 | 57 | San Francisco | 46 | 50 Hayward | 37 | 54 | San Francisco | 46 | 50(2 rows)
Qui abbiamo rietichettato la tabella meteo come W1 e W2 per poter distinguere il lato sinistro e destro dell’unione. Potete anche usare questo tipo di alias in altre query per risparmiare un po’ di battitura, ad esempio:
SELECT * FROM weather w, cities c WHERE w.city = c.name;
Incontrerete questo stile di abbreviazione abbastanza spesso.