Tot nu toe hebben onze queries slechts één tabel tegelijk benaderd. Queries kunnen meerdere tabellen tegelijk benaderen, of dezelfde tabel op zo’n manier dat meerdere rijen van de tabel tegelijk worden verwerkt. Een query die meerdere rijen van dezelfde of verschillende tabellen tegelijk benadert, wordt een join query genoemd. Stel bijvoorbeeld dat u een lijst wilt maken van alle weerrecords met de locatie van de bijbehorende stad. Om dat te doen, moeten we de kolom stad van elke rij van de weertabel vergelijken met de kolom naam van alle rijen in de steden-tabel, en de paren rijen selecteren waar deze waarden overeenkomen.
Note: Dit is slechts een conceptueel model. De join wordt meestal op een efficiëntere manier uitgevoerd dan het daadwerkelijk vergelijken van elk mogelijk paar rijen, maar dit is onzichtbaar voor de gebruiker.
Dit zou worden bereikt met de volgende 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)
Er zijn twee dingen te zien aan de resultaten:
-
Er is geen resultaatrij voor de stad Hayward. Dat komt omdat er in de tabel
cities
geen overeenkomende rij voor Hayward is, dus de join negeert de niet-overeenkomende rijen in de weertabel. We zullen zo zien hoe dit kan worden opgelost. - Er zijn twee kolommen met de plaatsnaam. Dit is correct omdat de kolommenlijsten van de
weather
en decities
tabel aan elkaar zijn gekoppeld. In de praktijk is dit echter ongewenst, dus zult u waarschijnlijk de output-kolommen expliciet willen opsommen in plaats van * te gebruiken:SELECT city, temp_lo, temp_hi, prcp, date, location FROM weather, cities WHERE city = name;
Oefening: Probeer de semantiek van deze query te achterhalen wanneer de WHERE-clausule wordt weggelaten.
Omdat de kolommen allemaal verschillende namen hebben, heeft de parser automatisch gevonden bij welke tabel ze horen, maar het is een goede stijl om kolomnamen in join query’s volledig te kwalificeren:
SELECT weather.city, weather.temp_lo, weather.temp_hi, weather.prcp, weather.date, cities.location FROM weather, cities WHERE cities.name = weather.city;
Join queries van het soort dat we tot nu toe hebben gezien, kunnen ook in deze alternatieve vorm worden geschreven:
SELECT * FROM weather INNER JOIN cities ON (weather.city = cities.name);
Deze syntaxis wordt niet zo vaak gebruikt als die hierboven, maar we laten hem hier zien om u te helpen de volgende onderwerpen te begrijpen.
Nu gaan we uitzoeken hoe we de Hayward-records er weer in kunnen krijgen. We willen dat de query de weather
tabel doorzoekt en voor elke rij de bijbehorende cities
rij zoekt. Als er geen overeenkomstige rij wordt gevonden, willen we dat er “lege waarden” worden gesubstitueerd voor de kolommen van de cities
tabel. Dit soort query wordt een outer join genoemd. (De joins die we tot nu toe hebben gezien zijn inner joins.) Het commando ziet er als volgt uit:
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)
Deze query wordt een left outer join genoemd omdat de tabel links van de join operator elke rij minstens één keer in de uitvoer zal hebben, terwijl de tabel rechts alleen die rijen uitvoer zal hebben die overeenkomen met een rij van de linker tabel. Wanneer een rij uit de linkertabel wordt uitgevoerd die niet overeenkomt met een rij uit de rechtertabel, worden de kolommen in de rechtertabel vervangen door lege (null) waarden.
Oefening: Er zijn ook right outer joins en full outer joins. Probeer uit te vinden wat die doen.
We kunnen ook een tabel tegen zichzelf joinen. Dit wordt een self join genoemd. Stel bijvoorbeeld dat we alle weerrecords willen vinden die in het temperatuurbereik van andere weerrecords liggen. Dus moeten we de temp_lo en temp_hi kolommen van elke weather
rij vergelijken met de temp_lo en temp_hi kolommen van alle andere weather
rijen. We kunnen dit doen met de volgende 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)
Hier hebben we de weertabel geherlabeld als W1 en W2 om onderscheid te kunnen maken tussen de linker- en rechterzijde van de join. Je kunt dit soort aliassen ook in andere queries gebruiken om wat typewerk te besparen, bijvoorbeeld:
SELECT * FROM weather w, cities c WHERE w.city = c.name;
Je zult deze manier van afkorten vrij vaak tegenkomen.