wtorek, 27 września 2016

MySQL PART II: i zapytania złożone...



Kolejna lekcja z zapytaniami złożonymi w "SIKUŁELU" za mną : )

Na początek kolejne fajne pojęcie związane z MySQLem, a bardzo przydatne podczas używania ORDER BY:

LIMIT 1* - *cyfra oznacza liczbę wyników do jakiej ograniczymy wyszukiwanie. Limity są szczególnie użyteczne, jeżeli układamy bazę danych np. ze względu na cenę i interesuje nas wykaz tylko jednej, najdroższej pozycji etc.

Okay, a teraz pojęcia i akcje związane z zapytaniami związanymi z łączeniem tabel, czyli dzisiejszego dania głównego:

Zapytanie złożone SELECT będzie mieć miejsce wtedy (jak się pewnie domyślasz), kiedy dane, jakie będziemy chcieli wyciągnąć z bazy znajdują się w więcej niż jednej tabeli. I to wcale nie będzie takie proste, ponieważ pomiędzy tabelami istnieją relacje.

Przy złożonych SELECTACH schemat wygląda następująco:

tabela.kolumna = czyli nazwatabeli.konkretnakolumna. przykład:

SELECT klienci.imie, klienci.nazwisko, zamowienia.idzamowienia, zamowienia.data (wybieramy konkretne dane z tabel klienci oraz z tabeli zamówienia, a z nich konkretne nazwy kolumn - kolejność dowolna, poszczególne zapytania oddzielamy zawsze przecinkiem) FROM klienci, zamówienia (tutaj określamy skąd te dane będą pochodzić - logicznie z tabel, z których wybieraliśmy konkretne informacje). Cały zapis bez tłumaczenia wygląda tak:



I teraz najważniejsze i trochę komplikujące sprawę info. Podczas tworzenia zapytań złożonych musisz dostarczyć listę wszystkich relacji, które zachodzą pomiędzy używanymi w tym zapytaniu tabelami!

Programista jest zobowiązany dostarczyć listę wszystkich relacji zachodzących pomiędzy używanymi w zapytaniu tabelami.

Tę listę należy umieścić po klauzuli WHERE..

Niestety.. Im więcej używamy w zapytaniu tabel, tym dłuższa będzie lista relacji :< Zapytania złożone, co nie?

Poprawmy zatem przykład z góry:



Raz jeszcze: po klauzuli WHERE musimy wypisać wszystkie relacje zachodzące pomiędzy używanymi przez nas w zapytaniu złożonym tabelami! Również wcale nie musi być tak, że po klauzuli WHERE kolumny, którym przypisujemy relacje muszą mieć takie same nazwy. Nie - nie muszą, bo i tak programista jest zobowiązany podać listę relacji. Konstrukcja tabela.kolumna jest opcjonalna! Jeżeli pośród wszystkich tabel występuje tylko jedna kolumna o nazwie 'x' to możemy ją zapisać jako "SELECT x" i wtedy MySQL domyśli się, że chodzi dokładnie o tę kolumnę. Gorzej, jeśli w paru tabelach występuje parę kolumn o tej samej nazwie - wtedy nie ma zmiłuj, piszesz schemat tabela.kolumna : )

I teraz trik. Zapytania złożone mają to do siebie, że mogą być długie. Szczęśliwie - możemy użyć tzw. "asliasów" (alias = przezwisko), by je skrócić. Np. zamiast pisać klienci.zamowienia można zapisać k.z (coś jak M jak Miłość).

Wystarczy te aliasy odpowiednio nadać i wtedy ten sam wpis będzie wyglądać w taki sposób:

SELECT k.imie, k.nazwisko, z.idzamowienia, z.data FROM klienci AS k, zamowienia AS z (tak, wlasnie tutaj nadalismy nasze aliasy) WHERE k.idklienta=z.idklienta

PIĘKNY KOMPROMIS : ) Należy jednak pamiętać, by używać stale raz nadanych aliasów. Złapałem się na tym, że jeśli w jednej linii kodu będziemy używać aliasów na przemian z pełnymi nazwami to nasze zapytanie nie da żadnego wyniku i maszyna zgłupieje. Tak czy siak, to końcowa optymalizacja działającego zapytania.

Co najważniejsze w pracy z tabelami, a już teraz rzuca mi się w oczy to DOKŁADNOŚĆ oraz LOGICZNE ZROZUMIENIE ZADAWANYCH PYTAŃ. Posiadanie wiedzy i narzędzi to jedno, a logiczne zrozumienie danego polecenia to drugie. Warto odpowiadać na zadane pytanie po kolei realizując już zadawane pytanie w formie kodu MySQL. I tak:

Wyselektuj imiona i nazwiska osób, które zamówiły kiedykolwiek książkę nr 2?

Wiemy, że mamy tutaj styczność z dwiema tabelami - tabelą, która będzie zawierać dane o klientach oraz tabelą, która będzie zawierać dane o zamówieniach. Piszmy już kod czytając pytanie:

Wiemy, że na pewno będzie nam potrzebne imię oraz nazwisko klienta, które będzie logicznie zawierać się w tabeli klienci, także: 

SELECT klienci.imie, klienci.nazwisko FROM klienci 

teraz dodajmy do tego informację, iż potrzebujemy z drugiej tabeli informacjęo książce nr dwa, zatem dodajmy magię do naszego kodu:

SELECT klienci.imie, klienci.nazwisko FROM klienci, zamowienia WHERE zamowienia.idksiazki = 2

Mamy teraz opisany warunek, wg. którego imię i nazwisko z tabeli klienci ma się wyświetlić w wynikach. Musimy jednak zaprogramować też relację pomiędzy tymi tabelami, także do kodu dodajemy już warunek AND (po WHERE nigdy nie piszemy przecinków!)

SELECT klienci.imie, klienci.nazwisko FROM klienci, zamowienia WHERE zamowienia.idksiazki = 2 AND klienci.idklienta=zamowienia.idklienta

Teraz jeszcze zoptymalizujmy kod aliasami:

SELECT k.imie, k.nazwisko FROM klienci AS k, zamowienia AS z WHERE z.idksiazki = 2 AND k.idklienta=z.idklienta

TADAM~! :)

Kolejne pytanie to: Jakie książki (tytuł, autor) zamówiła osoba: Jan Nowak?

Okay, sprawa wygląda następująco - najpierw w tabeli zamówienia sprawdzam sobie nr id klienta odpowiadającego Janowi Nowakowi i jest to cyfra nr. 2. Skąd takie ułatwienie? Ano, jeżeli klient zaloguje się na panel klienta to serwer z automatu przypisze mu jego id z tabeli klienci : ) Jedziemy z kodem!

Potrzebujemy tytułu oraz autora książki, także:

SELECT ksiazki.tytul, ksiazki.imieautora, ksiazki.nazwiskoautora FROM ksiazki, zamowienia WHERE zamowienia.idklienta=2 AND zamowienia.idksiazki=ksiazki.idksiazki

Teraz przejdźmy to wytłumaczenia reszty kodu.

SELECTEM wybraliśmy informację, jakie ma nam zwrócić serwer - tytuł, imię i nazwisko autora z tabeli książki (która posiada informację o książkach). Dane pobieraliśmy z (FROM) tabel książki oraz zamówienia (no bo klient musi wiedzieć co zamawiał, a te informację zawierają się w tej tabeli) oraz określiliśmy parametr gdzie (WHERE) zamowienia.idklienta=2 (oznaczamy tutaj Jana Nowaka, któremu system przydzielił już taki nr ID w tabeli klienci ale również ta kolumna zawarta jest przecież w ID zamówienia na zasadzie relacji pomiędzy nimi - logiczne) oraz opisaliśmy relację pomiędzy id książki na zasadzie porównania ich z tabelami zawierającymi info o zamówieniach oraz książkach. Mam nadzieję, że mnie rozumiesz? Kod oczywiście można zoptymalizować aliasami, gdzie ostatecznie będzie wyglądać tak:

SELECT k.tytul, k.imieautora, k.nazwiskoautora FROM ksiazki AS k, zamowienia AS z WHERE z.idklienta=2 AND z.idksiazki=k.idksiazki

No!

To teraz najtrudniejsze zadanie, bo będzie ono bazować na informacjach zawartych w trzech tabelach, pomiędzy którymi występują dwie relacje.

Pytanie brzmi: Zamówienia dokonane przez osoby o nazwisku Rutkowski ułożone wg daty od najpóźniej dokonanych (imię i nazwisko osoby zamawiającej, id, datę i status zamówienia, tytuł zamówionej książki)

No to znowu zadajemy sobie pytanie jakich informacji będziemy potrzebować i na bieżąco wklepywać kod:

SELECT klienci.imie, klienci.nazwisko, zamowienia.idzamowienia, zamowienia.data, zamowienia.status, ksiazki.tytul (tutaj określamy jakie informacje ma nam zwrócić serwer, to jest zrozumiałe) FROM klienci, zamowienia, ksiazki (tutaj określamy z jakich tabel serwer ma czerpać informacje. w tym przypadku będą to trzy tabele, ponieważ informacje jakich potrzebujemy zawierają się po trochu w każdej) WHERE klienci.nazwisko="Rutkowski" (tutaj określamy warunek, iż interesują nas tylko te rekordy w których występuję nazwisko Rutkowski z tabeli klienci) AND zamowienia.idklienta=klienci.idklienta (tutaj określamy relację pomiędzy informacjami z tabeli zamówienia oraz z tabeli klienci. wspólną kolumną będzie oczywiście idklienta) AND ksiazki.idksiazki=zamowienia.idksiazki (tutaj określamy drugą relację analogicznie, pomiędzy zamówieniami książki - id książki oraz samą nazwą książki, która jest tą samą wartością ale w tabeli książki i jest tam oczywiście PRIMARY KEYEM) ORDER BY zamowienia.data DESC (tutaj już porządkujemy ciąg wyświetlonych nam rekordów wg. daty zamówienia malejąco).

Kod przed optymalizacją wyglądać będzie tak:



Nie chce mi się go optymalizować :P

W ramach treningu zrobię sobie wieczorem kolejne fajne zadania na bazach danych, tak, by przed spaniem mózg znowu mi wyparował. W ramach mojej nauki korzystałem z niezawodnego vloga Mirosława Zelenta  :)



Pozdrówki!

Brak komentarzy:

Prześlij komentarz