#165 Rozdział 8. Łšczenie tabel W wielu wypadkach, w trakcie wyszukiwania informacji z bazy danych okazuje się, że potrzebne dane przechowywane sš w kilku tabelach. Nawet gdy potrzebne dane znajdujš się w jednej tabeli, możemy chcieć je porównać z danymi z innej tabeli, aby na tej podstawie wybrać tylko poprawne pozycje. Dużo czasu powięcono podczas projektowania struktury na rozdzielenie danych do wielu tabel w celu eliminacji nadmiarowoci. W celu połšczenia danych z wielu tabel w jednym zapytaniu wymagane jest złšczenie. Aby porównać dane z jednej tabeli z danymi z drugiej tabeli można wykonać złšczenie tabel lub podzapytanie (podzpytania omówiono w rozdziale 9.). W tym rozdziale omówię różne typy zapytań złšczajšcych i wyjanię, dlaczego wymaga ich relacyjny model baz danych. Przedstawione wczeniej techniki wybierania danych były stosowane do pojedynczych tabel. W tym rozdziale wyjanię, jak rozszerzyć te techniki na zapytania używajšcych wielu tabel. Połšczenia i normalizacja Podczas projektowania tabel ważne jest wykonanie normalizacji, żeby zapewnić spójnoć danych, tak aby ta sama porcja informacji nie pojawiała się w wielu tabelach. Dzięki temu w przyszłoci unikamy problemów przy aktualizacji danych. Niestety, oznacza to koniecznoć dostępu do wielu tabel w pojedynczym zapytaniu. Używajšc złšczeń między tabelami można wybierać informacje z wielu tabel za pomocš pojedynczej instrukcji SELECT. Daje to efekt ponownego połšczenia danych, które zostały rozdzielone do wielu tabel w trakcie normalizacji. #166 Co to jest złšczenie? Złšczenie (ang. join) to zapytanie, które łšczy dane z wielu tabel. Struktura standardowego zapytania wyglšda następujšco: SELECT column_list FROM table [ , table,...] [ WHERE condition] Główna różnica w składni pomiędzy instrukcjš SELECT wykorzystywanš w poprzednich rozdziałach, a instrukcjš SELECT wykorzystujšca złšczenia, polega na tym, że w częci FROM pojawiajš się deklaracje kilku tabel. Typowa pojedyncza instrukcja SELECT wyglšda następujšco: SELECT * FROM Movies Z drugiej strony instrukcja SELECT, która łšczy dwie tabele zawiera wiele wywołań tabel w częci table_list: SELECT * FROM Movies, Studios Problem z instrukcjš SELECT polega na tym, że zwraca ona każdš możliwš kombinację wierszy z dwóch tabel. Jeżeli tabela Movies zawiera 8 wierszy, a tabela Studios 10 wierszy to zapytanie zwróci 80 wierszy. Taki wynik jest rzadko pożšdany. Tworzenie sensownych złšczeń wymaga spełnienia dwóch warunków. Po pierwsze, należy wybrać w każdej tabeli kolumny, które sš ze sobš w logiczny sposób powišzane z kolumnami z drugiej tabeli. Po drugie, musi być zdefiniowane kryterium okrelajšce warunki złšczenia dwóch tabel. Przyjrzyjmy się tym dwu warunkom dokładniej. Zgodne kolumny Aby połšczenie dwóch tabel miało sens, muszš one mieć jakie wspólne dane. Zwróć uwagę, na listingi 8.1 i 8.2, które pokazujš dane z tabel Movies i People. ---------------------------- Listing 8.1. Kolumny title i directorjdz tabeli Moyies SELECT movie_title, director_id FROM Movies ORDER BY director id MOVIE_TITLE DIRECTOR_ID Minerał House 1 Condependence Day 1 The Programmer 1 The Rear Windows 1 The Code Warrior 2 The Linux Files 2 Bili Durham 9 Sql Strikes Back 9 Price Kong 10 Hard Code 10 Aws 10 rows selected ---------------------------- #167 ---------------------------- Listing 8.2. Kolumny person_id, person Jname i person_lname z tabeli People SELECT person_id, person_fname, person_lname FROM People ORDER BY person_id PERSON_ID PERSON_FNAME PERSON_LNAME ---------------------------- 1 Jeff Price 2 Chuck Peterson 3 Brandon Broołcs 4 Brian Smith 5 Paul Monk 6 Reece Randall 7 Peter Jong 8 Maggie Davies 9 Becky Orvis 10 Carol Delano 10 rows selected ---------------------------- Kolumna director_id z tabeli Movies odpowiada kolumnie person_id z tabeli People. Rzeczywicie, jeli jeszcze pamiętasz dyskusję na temat projektu bazy danych z rozdziału 3., to kolumna director_id jest kluczem obcym z tabeli People. W zwišzku z tym, że te dwie kolumny odpowiadajš sobie, można ich użyć do ustanowienia złšczenia między tabelami. W bardziej ogólnym znaczeniu kolumny z różnych tabel mogš być rozważane jako odpowiadajšce sobie (ang. join-compatybile), jeli zawierajš dane o tym samym znaczeniu. Sam fakt zgodnoci typów danych nie jest wystarczajšcy. Jeli dwie kolumny zawierajš dane typu Integer lub VARCHAR (20), to jeszcze nie wiadczy to o powišzaniu logicznym między kolumnami. Na przykład porównajmy kolumny person_id z tabeli People z kolumnš gross z tabeli Movies. Obie kolumny zawierajš liczby, ale nie ma żadnego powišzania między danymi z tych kolumn. W zwišzku z tym utworzenie złšczenia między tabelami poprzez te dwie kolumny jest możliwe, ale nie ma sensu. Z drugiej strony kolumny, o których wspomniałem na wstępie (director_id oraz person_id) mogš być wykorzystane do utworzenia zapytania, w którym wyszukamy imię i nazwisko reżysera każdego filmu z tabeli Movies. ---------------------------- Listing 8.3. Zapytanie łšczšce SELECT movie_title, person_fname, person_lname FROM Movies, People HHERE director_id - person_id MOVIE_TITLE PERSON_FNAME PERSON_LNAME ---------------------------- Minerał House Jeff Price Condependence Day Jeff Price The Programmer Jeff Price The Rear Windows Jeff Price The Code Warrior Chuck Peterson The Linux Files Chuck Peterson Bili Durham Becky Orvis Sql Strlkes Back Becky Orvis Price Kong Carol Delano Hard Code Carol Delano 10 rows selected ---------------------------- #168 Jak widać, kolumna movie_title z tabeli Movies oraz kolumny person_fname, person_lname z tabeli People znajdujš się na jednym zestawieniu. Klauzula WHERE okrela drugi warunek wymagany przy złšczeniu tabel w zapytaniu. Zwykle najefektywniejsze połšczenia osišgamy poprzez kolumny będšce kluczami w łšczonych tabelach. Na przykład zawsze można dokonać połšczenia tabel, jeli klucz główny jednej tabeli jest kluczem obcym w drugiej. =============== Rada W przypadku, gdy łšczymy tabelę, w której klucz główny stanowi kilka kolumn, należy użyć wszystkich kolumn klucza przy okrelaniu warunków połšczenia. Aby uzyskać prawidłowe połšczenie takich tabel, musisz w klauzuli WHERE wpisać ten złożony warunek. =================== Warunki złšczenia Napisanie efektywnego zapytania łšczšcego wymaga podania odpowiednich warunków połšczenia. Zwykle okrela się je wewnštrz klauzuli WHERE. W przypadku łšczenia kilku tabel wymagane jest podanie wielu warunków. Dla zapytania z listingu 8.3 warunek połšczenia okrelony jest przez wyrażenie director_id=person_id. Oznacza to, że jako wynik zapytania będš wybierane te wiersze tabel, dla których zachodzi podana równoć. Tabele nie muszš być otwarcie projektowane do konkretnych połšczeń. W przykładzie z listingu 8.3 tabele zostały połšczone w oparciu o relację klucza głównego i klucza obcego. Nie jest to jednak warunek konieczny do utworzenia złšczenia. Często bardziej interesujšce zestawienia można uzyskać poprzez relacje odkryte po utworzeniu bazy danych. Na przykład zapytanie z listingu 8.4 wybiera osoby żyjšce w tym samym miecie, w którym mieci się jakie studio filmowe. ---------------------------- Listing 8.4. Zapytanie łšczšce, znajduje osoby mieszkajšce w miastach, w których jest studio filmowe SELECT person_fname, person_lnarae, studio_name FROM People, Studios WHERE person_state - studio_state AND person_city - studio_city ---------------------------- Wartoci null nigdy nie sš traktowane jako spełniajšce warunek złšczenia. Wiersze, dla których w obu kolumnach łšczšcych znajdujš się wartoci null sš pomijane w wyniku zapytania. Wynika to stšd, że null traktowane sš jak wartoci nieokrelone i w zwišzku z tym, nie mogš być rozważane w kategorii równy, większy lub mniejszy. Używanie złšczeń Istnieje wiele zasad składniowych i innych technik zwišzanych z łšczeniem tabel. Wiele z nich wykorzystujemy w praktyce podczas tworzenia zapytań na podstawie kolumn z różnych tabel. #169 Na przykład kiedy łšczone kolumny z różnych tabel majš takie same nazwy, to nazwę kolumny powinnimy poprzedzić nazwš tabeli, z której pochodzi kolumna i kropkš. Na listingu 8.5 pokazano dostosowany do tej konwencji zapis zapytania z listingu 8.3. ---------------------------- Listing 8.5. Zapytanie w notacji tabela.kolumna SELECT Movies.movie_title, People.person_fname, People .person_lname FROM Movies, People WHERE Movies.director_id - People.person_id MOVIE_TITLE PERSON_FNAME PERSON_LNAME ---------------------------- Minerał House Jeff Price Condependence Day Jeff Price The Programmer Jeff Price The Rear Windows Jeff Price The Code Warrior Chuck Peterson The Linux Files Chuck Peterson Bili Durham Becky Orvis Sql Strikes Back Becky Orvis Price Kong Carol Delano Hard Code Carol Delano 10 rows selected ---------------------------- Jedyna różnica pomiędzy zapytaniami z listingów 8.3 i 8.5 polega na umieszczeniu przed nazwš kolumny nazwy odpowiedniej tabeli. Dopóki nazwy kolumn z obu tabel sš różne, taki zapis nie jest obowišzkowy. Jednak w przypadku złożonych zapytań warto przestrzegać tej zasady, nawet jeli nie jest to konieczne. Wybieranie kolumn Tworzšc zapytanie łšczšce kilka tabel rzadko wybieramy wszystkie kolumny przy pomocy symbolu *.Użycie tego symbolu powoduje, że wszystkie kolumny ze wszystkich tabel pojawiš się w zestawieniu wynikowym. Jak się pewnie domylasz, to z kolei obniża przejrzystoć wyników zapytania. Listing 8.6 przedstawia wynik zapytania wybierajšcego wszystkie kolumny z tabel. ---------------------------- Listing 8.6. Zapytanie łšczšce, które wybiera wszystkie kolumny ...
sliwak