Do tej pory nasze zapytania miały dostęp tylko do jednej tabeli na raz. Zapytania mogą mieć dostęp do wielu tabel jednocześnie lub do tej samej tabeli w taki sposób, że wiele wierszy tabeli jest przetwarzanych w tym samym czasie. Zapytanie, które uzyskuje dostęp do wielu wierszy z tej samej lub różnych tabel w tym samym czasie nazywane jest zapytaniem łączącym. Na przykład, powiedzmy, że chcemy wyświetlić listę wszystkich rekordów pogodowych wraz z lokalizacją powiązanego z nimi miasta. Aby to zrobić, musimy porównać kolumnę miasto w każdym wierszu tabeli pogoda z kolumną nazwa we wszystkich wierszach tabeli miasta i wybrać pary wierszy, w których te wartości są zgodne.
Uwaga: To jest tylko model koncepcyjny. Dołączenie jest zwykle wykonywane w bardziej wydajny sposób niż faktyczne porównywanie każdej możliwej pary wierszy, ale jest to niewidoczne dla użytkownika.
Osiągnęłoby to następujące zapytanie:
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)
Zwróć uwagę na dwie rzeczy dotyczące zestawu wyników:
-
Nie ma żadnego wiersza wyniku dla miasta Hayward. Dzieje się tak, ponieważ nie ma pasującego wpisu w tabeli
cities
dla Hayward, więc złączenie ignoruje niedopasowane wiersze w tabeli pogody. Zobaczymy wkrótce jak można to naprawić. -
Istnieją dwie kolumny zawierające nazwę miasta. Jest to poprawne, ponieważ listy kolumn tabeli
weather
icities
są połączone. W praktyce jest to jednak niepożądane, więc prawdopodobnie będziesz chciał wymienić kolumny wyjściowe jawnie, zamiast używać *:SELECT city, temp_lo, temp_hi, prcp, date, location FROM weather, cities WHERE city = name;
Ćwiczenie: Spróbuj poznać semantykę tego zapytania, gdy klauzula WHERE jest pominięta.
Ponieważ wszystkie kolumny miały różne nazwy, parser automatycznie ustalił, do której tabeli należą, ale dobrym stylem jest pełne kwalifikowanie nazw kolumn w zapytaniach typu join:
SELECT weather.city, weather.temp_lo, weather.temp_hi, weather.prcp, weather.date, cities.location FROM weather, cities WHERE cities.name = weather.city;
Kwerendy join w takiej formie, jaką widzieliśmy do tej pory, mogą być również napisane w tej alternatywnej formie:
SELECT * FROM weather INNER JOIN cities ON (weather.city = cities.name);
Ta składnia nie jest tak powszechnie używana jak powyższa, ale pokazujemy ją tutaj, aby ułatwić zrozumienie kolejnych tematów.
Teraz zastanowimy się, w jaki sposób możemy odzyskać rekordy Hayward. Chcemy, aby zapytanie przeskanowało tabelę weather
i dla każdego wiersza znalazło pasujący cities
wiersz. Jeśli nie znajdziemy pasującego wiersza chcemy, aby w kolumnach tabeli cities
zostały podstawione jakieś „puste wartości”. Tego typu zapytanie nazywane jest złączeniem zewnętrznym. Polecenie wygląda następująco:
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)
Zapytanie to nazywane jest złączeniem zewnętrznym lewym, ponieważ tabela wymieniona po lewej stronie operatora złączenia będzie miała każdy ze swoich wierszy na wyjściu przynajmniej raz, podczas gdy tabela po prawej stronie będzie miała tylko te wiersze, które pasują do któregoś z wierszy tabeli lewej. Podczas wyprowadzania wiersza lewej tabeli, dla którego nie ma dopasowania w prawej tabeli, puste (null) wartości są zastępowane kolumnami prawej tabeli.
Ćwiczenie: Istnieją również right outer joins oraz full outer joins. Spróbuj dowiedzieć się co one robią.
Możemy również dołączyć do tabeli względem niej samej. Nazywa się to złączeniem własnym. Jako przykład, załóżmy, że chcemy znaleźć wszystkie rekordy pogodowe, które są w zakresie temperatur innych rekordów pogodowych. Musimy więc porównać kolumny temp_lo i temp_hi każdego wiersza weather
z kolumnami temp_lo i temp_hi wszystkich pozostałych weather
wierszy. Możemy to zrobić za pomocą następującego zapytania:
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)
Tutaj zmieniliśmy nazwy tabeli pogody na W1 i W2, aby móc rozróżnić lewą i prawą stronę złączenia. Tego typu aliasów można również używać w innych zapytaniach, aby zaoszczędzić trochę pisania, np.:
SELECT * FROM weather w, cities c WHERE w.city = c.name;
Z tym stylem skracania można się spotkać dość często.