Akademia Morska w Gdyni Gdynia 2004
1. Złączenie definicja Złączenie (JOIN) to zbiór rekordów stanowiących wynik zapytania służącego pobraniu danych z połączonych tabel (związki jeden-do-jeden, jeden-do-wiele lub wiele-do-wiele ). Istnieją dwa podstawowe sposoby konstruowania złączeń (instrukcja SELECT): 1. łączone tabele w klauzuli FROM i warunki złączenia w WHERE 2. zastosowanie instrukcji JOIN w ramach składni instrukcji SELECT W czasie konstrukcji zapytań ze złączeniem dowolnego typu bardzo pomocne okazują się rozszerzone diagramy związków encji (E-R), na których ujęta jest zależność klucz obcy-klucz główny łączonych tabeli (a więc tabeli mogących podlegać złączeniu). wydawnictwa ksiazki ksiazki_autorzy autorzy nazwa ulica miasto telefon fax numer konta tytul cena isbn data_wydania wydawnictwa_ ksiazki_ autorzy_ imie nazwisko tytul_naukowy wiek Legenda: klucz główny klucz obcy Rysunek 1 Rozszerzony diagram E-R dla bazy danych wykorzystywanej na zajęciach 1.1. Złączenie z użyciem FROM i WHERE W przypadku dwóch tabel, połączonych za pomocą klucza obcego wskazującego na klucz główny drugiej tabeli (związki jeden-do-jeden i jeden-do-wiele ), najczęściej chcemy zawęzić wynik iloczynu kartezjańskiego tych tabel, który byłyby zwrócony przez proste zapytanie np.: SELECT * from ksiazki, wydawnictwa; Ze zbioru wszystkich par rekordów k i w, takich, że rekord k pochodzi z tabeli ksiazki a rekord w z tabeli wydawnictwa (związek jeden-do-wiele, wiele książek w ramach jednego wydawnictwa), chcemy wybrać tylko te pary rekordów k i w dla których prawdziwy jest związek: książka określona rekordem k została wydana przez Joanna Szłapczyńska (asiasz@am.gdynia.pl) Strona 2 z 7
wydawnictwo w. Taką operację można zrealizować w oparciu o znaną już klauzulę filtracji wyników WHERE: SELECT * from ksiazki, wydawnictwa WHERE ksiazki.wydawnictwa_=wydawnictwa.; Aby zapewnić prawłowy dostęp do pól (np. kolumna ID występuje zarówno w tabeli ksiazki jak również w tabeli wydawnictwa) w powyższym przykładzie zastosowano kwalifikator : <nazwa_tabeli>.<nazwa_kolumny>. wydało: SELECT ksiazki.tytul, wydawnictwa.nazwa from ksiazki, wydawnictwa WHERE ksiazki.wydawnictwa_=wydawnictwa.; Uwaga: W przypadku złączeń definiowanych za pomocą klauzul FROM i WHERE (sposób 1.) RDBMS najpierw tworzy wstępny zbiór wyników będący iloczynem kartezjańskim, a dopiero później wyszukuje te rekordy, które spełniają zadany warunek w klauzuli WHERE. 1.2. Złączenie z użyciem klauzuli JOIN W przypadku stosowania klauzuli JOIN zbiór wstępnych wyników jest najczęściej znacznie mniejszy, ograniczany jest warunkiem po słowie kluczowym ON. Złączenia konstruowane zgodnie ze sposobem 2. wymagają użycia instrukcji JOIN w miejscu nazw tabel po słowie kluczowym FROM instrukcji SELECT. Składnia instrukcji JOIN (http://www.mysql.com/doc/en/join.html): table_reference, table_reference table_reference [INNER CROSS] JOIN table_reference [join_condition] table_reference STRAIGHT_JOIN table_reference table_reference LEFT [OUTER] JOIN table_reference [join_condition] table_reference NATURAL [LEFT [OUTER]] JOIN table_reference { OJ table_reference LEFT OUTER JOIN table_reference ON conditional_expr } table_reference RIGHT [OUTER] JOIN table_reference [join_condition] table_reference NATURAL [RIGHT [OUTER]] JOIN table_reference Joanna Szłapczyńska (asiasz@am.gdynia.pl) Strona 3 z 7
gdzie table_reference jest zdefiniowane jako: table_name [[AS] alias] [[USE INDEX (key_list)] [IGNORE INDEX (key_list)] [FORCE INDEX (key_list)]] a join_condition jest zdefiniowany jako: ON conditional_expr USING (column_list) Kolejne rozdziały opracowania omawiają główne typy złączeń realizowanych w oparciu o instrukcję JOIN wraz z przykładami. 2. Złączenia wewnętrzne (INNER JOIN) Złączenie wewnętrzne (INNER JOIN) to zbiór rekordów będący iloczynem kartezjańskim łączonych tabel ograniczony przez dodatkowe warunki złączenia, najczęściej są to warunki równości kluczy głównego i obcego (tzw. złączenie równościowe - EQUIJOIN). Równoważne składnie złączeń wewnętrznych: 1. SELECT <kolumna_1>,...<kolumna_n> from <nazwa_tabeli_1>, <nazwa_tabeli_2> WHERE <warunek_połączenia> 2. SELECT <kolumna_1>,...<kolumna_n> from <nazwa_tabeli_1> INNER JOIN <nazwa_tabeli_2> {ON <warunek_połączenia> USING <lista kolumn>} 3. SELECT <kolumna_1>,...<kolumna_n> from <nazwa_tabeli_1> CROSS JOIN 4. SELECT <kolumna_1>,...<kolumna_n> from <nazwa_tabeli_1> JOIN Ponieważ domyślnym typem złączenia (JOIN) jest w MySQL złączenie wewnętrzne składnie JOIN oraz INNER JOIN są równoważne. Polecenie CROSS JOIN, służące do realizacji iloczynu kartezjańskiego, jest również tożsame ze złączeniem wewnętrznym INNER JOIN w sytuacji, gdy CROSS JOIN posiada określony warunek złączenia. wydało (równoważne składniowo sposoby): Joanna Szłapczyńska (asiasz@am.gdynia.pl) Strona 4 z 7
SELECT ksiazki.tytul, wydawnictwa.nazwa from ksiazki, wydawnictwa WHERE ksiazki.wydawnictwa_=wydawnictwa.; SELECT ksiazki.tytul, wydawnictwa.nazwa from ksiazki INNER JOIN wydawnictwa ON ksiazki.wydawnictwa_=wydawnictwa.; SELECT ksiazki.tytul, wydawnictwa.nazwa from ksiazki CROSS JOIN wydawnictwa ON ksiazki.wydawnictwa_=wydawnictwa.; SELECT ksiazki.tytul, wydawnictwa.nazwa from ksiazki JOIN wydawnictwa ON ksiazki.wydawnictwa_=wydawnictwa.; Uwaga: W przypadku, jeśli jedna z porównywanych kolumn (w równościowym warunku złączenia) przyjmuje wartość NULL jej wartość nie znajdzie się w wyniku tego złączenia (zgodnie z ogólnymi zasadami obsługiwania wartości NULL przez operacje porównania). Jest to ważna cecha charakterystyczna złączeń wewnętrznych. W powyższym przykładzie złączenie wewnętrzne nie zawiera ani tych wydawnictw, które nie wydały żadnej książki ani też tych książek, dla których jeszcze nie znaleziono wydawcy. Składnia języka SQL umożliwia nadawanie aliasów nazwom tabel, co znacznie ułatwia odwoływanie się do kolumn poprzez kwalifikator <alias>.<nazwa_kolumny> zamiast: <nazwa_tabeli>.<nazwa_kolumny> wydało przy wykorzystaniu aliasowania nazw tabel: SELECT k.tytul, w.nazwa from ksiazki AS k INNER JOIN wydawnictwa AS w ON k.wydawnictwa_=w.; Jeśli łączone tabele posiadają te same nazwy kolumn łączących (kluczy obcych i kluczy głównych) możemy zastosować jedną z równoważnych klauzul: USING lub też NATURAL JOIN zgodnie ze składnią:... A INNER JOIN B USING (<nazwa_kolumny_1>,..., <nazwa_kolumny_1>)..... A NATURAL JOIN B Joanna Szłapczyńska (asiasz@am.gdynia.pl) Strona 5 z 7
Wywołanie z użyciem klauzuli USING wymaga, aby obie łączone tabele posiadały wszystkie pola wymienione na liście. Natomiast złączenie NATURAL JOIN oznacza złączenie wewnętrzne dla warunku równości wszystkich kolumn o tych samych nazwach w łączonych tablicach (uwaga: nie jest wymagane specyfikowanie nazw kolumn i RDBMS automatycznie wyszukuje kolumny o tych samych nazwach!). wydało, przy założeniu, że tablica ksiązki ma zdefiniowany klucz główny jako ksiazki_ oraz klucz obcy jako wydawnictwa_ oraz tablica wydawnictwa ma zdefiniowany klucz główny jako wydawnictwa_ (równoważne sposoby): SELECT ksiazki.tytul, wydawnictwa.nazwa from ksiazki INNER JOIN wydawnictwa USING (wydawnictwa_); SELECT ksiazki.tytul, wydawnictwa.nazwa from ksiazki NATURAL JOIN wydawnictwa; 3. Złączenia zewnętrzne (OUTER JOIN) Złączenia zewnętrzne (OUTER JOIN) rozszerzają pojęcie złączenia wewnętrznego zwracając rekordy, które spełniają określone warunki złączenia oraz wszystkie inne rekordy z jednej (lub obu) łączonych tabel. Wyróżniamy następujące typy złączeń zewnętrznych: Złączenie lewe (LEFT JOIN) rozszerza zbiór rekordów złączenia wewnętrznego o te rekordy z tablicy z lewej strony złączenia, dla których nie przyporządkowano żadnych odpowiadających rekordów z tablicy prawej w złączeniu Złączenie prawe (RIGHT JOIN) analogicznie do złączenia lewego, tylko odpowiednio dla prawej strony złączenia Złączenie zewnętrzne pełne (FULL JOIN) - rozszerza zbiór rekordów złączenia wewnętrznego o te rekordy z tablicy z lewej oraz prawej złączenia, dla nie przyporządkowano żadnych odpowiadających rekordów z łączonej tablicy Składnia złączeń zewnętrznych w MySQL: Złączenie lewe (LEFT JOIN) Joanna Szłapczyńska (asiasz@am.gdynia.pl) Strona 6 z 7
SELECT <kolumna_1>,...<kolumna_n> from <nazwa_tabeli_1> LEFT JOIN Złączenie prawe (RIGHT JOIN) SELECT <kolumna_1>,...<kolumna_n> from <nazwa_tabeli_1> RIGHT JOIN Złączenie pełne (FULL JOIN) W obecnej wersji MySQL (4.1.1) złączenie pełne nie jest obsługiwane. Wyświetlenie pełnej listy nazw wydawnictw wraz z wydanymi przez nie książkami (z uwzględnieniem tych wydawnictw, które do tej pory nie wydały żadnej książki) (równoważne sposoby): SELECT ksiazki.tytul, wydawnictwa.nazwa from wydawnictwa LEFT JOIN ksiazki on ksiazki.wydawnictwa_=wydawnictwa.; SELECT ksiazki.tytul, wydawnictwa.nazwa from ksiazki RIGHT JOIN wydawnictwa on ksiazki.wydawnictwa_=wydawnictwa.; Dopuszczalne jest również tworzenie złączenia (wewnętrznego lub zewnętrznego) kilkukrotnie, tak aby zrealizować połączenie więcej niż dwóch tabel. Np. dla złączenia tabel A, B i C stosujemy notację: FROM A JOIN B ON <warunek_zlaczenia_1> JOIN C ON <warunek_zlaczenia_2> Wyświetlenie pełnej listy autorów wraz z tytułami książek które napisali (z uwzględnieniem tych autorów, którzy na razie nie wydali żadnej książki): SELECT imie, nazwisko, tytul FROM autorzy LEFT JOIN ksiazki_autorzy ON ksiazki_autorzy.autorzy_=autorzy. LEFT JOIN ksiazki ON ksiazki_autorzy.ksiazki_=ksiazki. ORDER BY nazwisko; Joanna Szłapczyńska (asiasz@am.gdynia.pl) Strona 7 z 7