SlideShare a Scribd company logo
PHP6 i MySQL 5.
Dynammiczne strony www.
Szybki start
Autor: Larry Ullman
T³umaczenie: Jaromir Senczyk
ISBN: 978-83-246-1723-4
Tytu³ orygina³u: PHP 6 and MySQL 5
for Dynamic Web Sites: Visual QuickPro Guide
Format: 170x230, stron: 640

        Poznaj mo¿liwoœci PHP6 oraz MySQL 5 i twórz dynamiczne strony WWW
    • Jak utworzyæ podstawowy skrypt PHP?
    • Jak korzystaæ z wielowymiarowych tablic?
    • Jak budowaæ bazy danych?
Ka¿da funkcjonalna i atrakcyjna dla u¿ytkowników strona internetowa musi byæ
na bie¿¹co aktualizowana, a umieszczone na niej interesuj¹ce informacje powinny byæ
³atwo dostêpne. Najpopularniejsze narzêdzia typu open source, s³u¿¹ce do tworzenia
dynamicznych witryn, to jêzyk PHP i system zarz¹dzania relacyjnymi bazami danych
MySQL. Oba te narzêdzia oferuj¹ wysok¹ wydajnoœæ, przenoœnoœæ i niezawodnoœæ.
Wœród wielu ogromnych mo¿liwoœci oraz zalet PHP i MySQL maj¹ tak¿e tak¹, ¿e
sprawne pos³ugiwanie siê nimi nie jest zbyt skomplikowane nawet dla pocz¹tkuj¹cych.
Ksi¹¿ka „PHP6 i MySQL 5. Dynamiczne strony WWW. Szybki start” zawiera precyzyjny
opis czynnoœci oraz bogato ilustrowane zrzutami ekranu niezbêdne wskazówki
i wyjaœnienia, u³atwiaj¹ce samodzielne zbudowanie dynamicznej strony internetowej.
Dziêki temu podrêcznikowi nauczysz siê wyszukiwaæ i usuwaæ b³êdy w skryptach PHP,
tworzyæ formularze w jêzyku HTML oraz zapobiegaæ atakom na Twoje witryny. Poznasz
tak¿e podstawowe i zaawansowane techniki tworzenia ró¿nych aplikacji (na przyk³ad
stron wielojêzycznych lub obs³uguj¹cych fora dyskusyjne).
    • PHP i MySQL
    • Tworzenie formularza w jêzyku HTML
    • Tablice i ³añcuchy
    • Tworzenie i wywo³ywanie w³asnych funkcji
    • Wype³nianie baz danych
    • Zabezpieczenia
    • Stosowanie modyfikatorów
    • Szyfrowanie danych
    • Tworzenie uniwersalnych witryn
    • Budowanie strony domowej
    • Wielojêzyczna strona WWW
    • Tworzenie kont u¿ytkowników i nadawanie uprawnieñ
                    Szybko i ³atwo naucz siê tworzyæ funkcjonalne
                        oraz bezpieczne witryny internetowe
Spis treści

              Wprowadzenie                                                                                                                  9
              Czym są dynamiczne strony WWW? ................................................................... 10
              Co będzie Ci potrzebne? ....................................................................................... 16
              O tej książce ........................................................................................................... 17

Rozdział 1.   Wprowadzenie do PHP                                                                                                          19
              Podstawy składni.................................................................................................... 20
              Przesyłanie danych do przeglądarki internetowej ............................................... 24
              Wstawianie komentarzy......................................................................................... 28
              Co to są zmienne? .................................................................................................. 32
              Łańcuchy ................................................................................................................ 36
              Łączenie łańcuchów............................................................................................... 39




                                                                                                                                                      Spis treści
              Liczby ..................................................................................................................... 41
              Stałe ........................................................................................................................ 45
              Apostrof kontra cudzysłów .................................................................................... 48

Rozdział 2.   Programowanie w PHP                                                                                                          51
              Tworzenie formularza w języku HTML ............................................................... 52
              Obsługa formularza HTML................................................................................... 56
              Wyrażenia warunkowe i operatory ....................................................................... 60
              Weryfikacja danych pochodzących z formularza ................................................. 64
              Co to są tablice? ..................................................................................................... 70
              Pętle for i while ...................................................................................................... 88

Rozdział 3.   Tworzenie dynamicznych stron WWW                                                                                             91
              Wykorzystywanie plików zewnętrznych .............................................................. 92
              Wyświetlanie i obsługa formularza przez jeden skrypt ....................................... 102
              Tworzenie formularzy z pamięcią ....................................................................... 107
              Tworzenie i wywoływanie własnych funkcji ...................................................... 110

Rozdział 4.   Wprowadzenie do MySQL                                                                                                       125
              Elementy bazy danych i ich nazwy..................................................................... 126
              Wybór typu kolumny ........................................................................................... 128
              Wybór innych właściwości kolumn .................................................................... 132
              Korzystanie z serwera MySQL-a ........................................................................ 134

                                                                                                                                                  5
Spis treści


              Rozdział 5.   Wprowadzenie do SQL                                                                                                     141
                            Tworzenie baz danych i tabel.............................................................................. 142
                            Wprowadzanie rekordów..................................................................................... 145
                            Wybieranie danych .............................................................................................. 149
                            Wyrażenia warunkowe ........................................................................................ 151
                            Stosowanie LIKE i NOT LIKE .......................................................................... 154
                            Sortowanie wyników zapytania ........................................................................... 156
                            Ograniczanie wyników zapytania........................................................................ 158
                            Uaktualnianie danych .......................................................................................... 160
                            Usuwanie danych ................................................................................................. 162
                            Funkcje ................................................................................................................. 164
              Rozdział 6.   Zaawansowany SQL i MySQL                                                                                                175
                            Projekt bazy danych............................................................................................. 176
                            Złączenia............................................................................................................... 191
                            Grupowanie wyników zapytania ......................................................................... 196
                            Indeksy ................................................................................................................. 198
                            Stosowanie różnych typów tabeli........................................................................ 203
                            Wyszukiwanie FULLTEXT ................................................................................ 206
Spis treści




                            Wykonywanie transakcji...................................................................................... 212
              Rozdział 7.   Obsługa i usuwanie błędów                                                                                               217
                            Ogólne typy błędów i ich usuwanie.................................................................... 218
                            Wyświetlanie błędów PHP.................................................................................. 224
                            Sterowanie raportowaniem błędów PHP ........................................................... 226
                            Tworzenie własnych funkcji obsługi błędów ..................................................... 229
                            Techniki usuwania błędów z PHP ...................................................................... 234
                            Techniki usuwania błędów SQL i MySQL ........................................................ 238
              Rozdział 8.   PHP i MySQL                                                                                                            241
                            Modyfikacja szablonu .......................................................................................... 242
                            Łączenie się z MySQL-em i wybieranie bazy.................................................... 244
                            Wykonywanie prostych zapytań.......................................................................... 248
                            Odczytywanie wyników zapytania ...................................................................... 257
                            Bezpieczeństwo zapytań...................................................................................... 261
                            Zliczanie zwróconych rekordów ......................................................................... 267
                            Uaktualnianie rekordów w PHP ......................................................................... 269
              Rozdział 9.   Tworzenie aplikacji internetowych                                                                                      277
                            Przekazywanie wartości do skryptu..................................................................... 278
                            Stosowanie ukrytych pól formularza................................................................... 282
                            Edycja istniejących rekordów ............................................................................. 288

              6
Spis treści

             Stronicowanie wyników zapytań......................................................................... 295
             Wyświetlanie tabel z możliwością sortowania.................................................... 303

Rozdział 10. Tworzenie aplikacji internetowych                                                                                        309
             Wysyłanie poczty elektronicznej ........................................................................ 310
             Funkcje daty i czasu............................................................................................. 316
             Obsługa przesyłania plików................................................................................. 320
             Skrypty PHP i JavaScript .................................................................................... 333
             Nagłówki HTTP ................................................................................................... 340

Rozdział 11. Sesje i „ciasteczka”                                                                                                      345
             Strona logowania .................................................................................................. 346
             Funkcje logowania ............................................................................................... 349
             Posługiwanie się ciasteczkami............................................................................. 354
             Sesje ...................................................................................................................... 367
             Zwiększanie bezpieczeństwa sesji ...................................................................... 376

Rozdział 12. Zabezpieczenia                                                                                                            379
             Zapobieganie spamowi ........................................................................................ 380




                                                                                                                                                    Spis treści
             Walidacja danych według typu ........................................................................... 387
             Zapobieganie atakom XSS ................................................................................... 392
             Zapobieganie wstrzykiwaniu poleceń SQL........................................................ 395
             Szyfrowanie i bazy danych .................................................................................. 401

Rozdział 13. Wyrażenie regularne Perl                                                                                                 407
             Skrypt testujący.................................................................................................... 408
             Definiowanie prostych wzorców......................................................................... 412
             Stosowanie kwantyfikatorów ............................................................................... 415
             Klasy znaków ........................................................................................................ 418
             Wyszukiwanie wszystkich dopasowań................................................................ 421
             Stosowanie modyfikatorów.................................................................................. 425
             Dopasowywanie i zastępowanie wzorców.......................................................... 427

Rozdział 14. Tworzenie uniwersalnych witryn                                                                                            431
             Zbiory znaków i kodowanie................................................................................. 432
             Tworzenie wielojęzycznych stron WWW .......................................................... 434
             Unicode w PHP ................................................................................................... 438
             Uporządkowanie zbioru znaków w PHP ............................................................ 442
             Transliteracja w PHP........................................................................................... 445
             Języki i MySQL.................................................................................................... 448
             Strefy czasowe i MySQL ..................................................................................... 452
             Lokalizatory .......................................................................................................... 455

                                                                                                                                                7
Spis treści


              Rozdział 15. Forum dyskusyjne — przykład                                                                                            459
                            Baza danych.......................................................................................................... 460
                            Szablony................................................................................................................ 469
                            Strona domowa..................................................................................................... 478
                            Strona forum......................................................................................................... 479
                            Strona wątku......................................................................................................... 484
                            Wstawianie wiadomości....................................................................................... 489

              Rozdział 16. Rejestracja użytkowników — przykład                                                                                     501
                            Tworzenie szablonu ............................................................................................. 502
                            Skrypty konfiguracyjne........................................................................................ 508
                            Tworzenie strony domowej ................................................................................. 516
                            Rejestracja ............................................................................................................ 518
                            Aktywacja konta ................................................................................................... 527
                            Logowanie i wylogowywanie się......................................................................... 531
                            Zarządzanie hasłami............................................................................................. 537

              Rozdział 17. Sklep internetowy — przykład                                                                                            547
                            Tworzenie bazy danych ....................................................................................... 548
Spis treści




                            Część administracyjna aplikacji .......................................................................... 554
                            Tworzenie szablonu części publicznej aplikacji................................................. 571
                            Katalog produktów............................................................................................... 575
                            Koszyk................................................................................................................... 587
                            Rejestrowanie zamówień ..................................................................................... 597

              Dodatek A     Instalacja                                                                                                            605
                            Instalacja w systemie Windows .......................................................................... 606
                            Definiowanie uprawnień MySQL....................................................................... 609
                            Testowanie instalacji............................................................................................ 613
                            Konfigurowanie PHP........................................................................................... 616

                            Skorowidz                                                                                                              619




              8
Zaawansowany SQL i MySQL                                                        6
Rozdział 6. Zaawansowany SQL i MySQL

Rozdział ten zaczyna się w miejscu, w którym ostatni się kończył. Omówię w nim bardziej
zaawansowane zagadnienia dotyczące SQL-a i MySQL-a. Poznałeś już podstawy obu tych
technologii i z pewnością wystarczą Ci one do realizacji wielu projektów, ale dopiero ich
bardziej wyszukane możliwości wyniosą Twe aplikacje internetowe na wyższy poziom.
Zacznę od szczegółowego omówienia procesu projektowania bazy danych, opierając się
na przykładzie systemu zarządzania forum. Doprowadzi nas to oczywiście do tematu
złączeń, będących integralną częścią każdej relacyjnej bazy danych. Następnie będę
opisywał kolejną kategorię funkcji wbudowanych MySQL-a używanych do grupowania
wyników zapytań.
Na zakończenie przejdę do bardziej zaawansowanych zagadnień. Powiem o indeksach,
nauczę Cię zmieniać strukturę istniejących tabel oraz omówię typy tabel dostępne
w MySQL-u. Rozdział zakończę omówieniem dwóch dodatkowych możliwości MySQL-a:
przeszukiwania tekstów i transakcji.




                                                                                            Zaawansowany SQL i MySQL




                                                                                      175
Rozdział 6.


                      Projekt bazy danych                                  W moim przykładowym systemie będę chciał
                                                                           stworzyć forum, na którym użytkownicy mogą
                      Pierwsze, co musisz zrobić, gdy pracujesz z systemem zamieszczać swoje opinie i odpowiadać innym
                      zarządzania relacyjnymi bazami danych, takim jak internautom. Aby korzystać z forum, użytkownik
                      MySQL, to utworzyć strukturę bazy (zwaną również będzie musiał się zarejestrować, a następnie
                      schematem bazy danych). Projektowanie bazy danych uwierzytelnić za pomocą kombinacji nazwy i hasła.
                      lub inaczej modelowanie danych to niezbędny etap Przewiduję również możliwość istnienia wielu
                      gwarantujący długotrwałe i bezproblemowe zarządzanie forów poświęconych różnym tematom. W tabeli
                      Twoimi informacjami. W procesie zwanym normalizacją 6.1 pokazałem, jak wygląda przykładowy rekord.
                      eliminuje się niepotrzebne powtórzenia informacji    Baza danych będzie nosić nazwę forum.
                      i inne problemy, które zagrażają spójności danych.
                                                                               Wskazówki
                      Dzięki technikom, które poznasz w tym rozdziale,
                      Twoje bazy będą wydajne i niezawodne. Jeden                 Istnieje bardzo dobra metoda na określenie,
                      z przykładów, które zaprezentuję — forum, na którym         jakiego rodzaju informacje powinny się
                      użytkownicy mogą wymieniać się opiniami — będzie            znaleźć w bazie danych. Wystarczy,
                      intensywnie wykorzystywany dopiero w rozdziale 15.,         że zastanowisz się, jakiego rodzaju pytania
                      „Forum dyskusyjne — przykład”. Jednak omówione              o dane będą zadawane przez użytkowników
                      przeze mnie zasady normalizacji odnoszą się                 i jakie dane będą musiały się znaleźć
                      do wszystkich aplikacji bazodanowych, jakie możesz          w odpowiedziach.
                      utworzyć. (Przykład bazy sitename używany                   Nauka normalizacji może sprawić Ci trudności,
                      w poprzednich dwóch rozdziałach został poprawnie            jeśli niepotrzebnie skoncentrujesz się na
                      zaprojektowany również z punktu widzenia normalizacji,      szczegółach. Każda z postaci normalnych jest
                      ale zagadnienie to nie zostało jeszcze omówione.)           zdefiniowana w dość skomplikowany sposób,
                                                                                  a próba przełożenia tych definicji na język
Projekt bazy danych




                      Normalizacja                                                niefachowy może być myląca. Dlatego radzę
                      Proces normalizacji został wymyślony na początku lat        Ci, abyś podczas lektury omówienia postaci
                      siedemdziesiątych przez E.F. Codda, naukowca z firmy        normalnych skoncentrował się na ogólnym
                      IBM, który wymyślił też relacyjne bazy danych. Tego         obrazie zmian zachodzących w schemacie
                      rodzaju bazy to nic innego jak tylko zbiór danych           bazy danych. Po zakończeniu normalizacji
                      ułożonych w pewien określony sposób. Istnieje szereg        i otrzymaniu końcowej postaci bazy danych
                      tak zwanych postaci normalnych (NF, z ang. Normal           cały proces powinien stać się dla Ciebie
                      Form), które ułatwiają definiowanie struktury danych.       wystarczająco zrozumiały.
                      W tym rozdziale omówię pierwsze trzy z nich,          Tabela 6.1. Przykładowy rekord pokazujący, jakiego
                      ponieważ w większości przypadków są one w pełni rodzaju informacje chcę przechowywać w mojej
                      wystarczające.                                        bazie danych
                      Zanim zaczniesz normalizować swoją bazę danych,          Przykładowe dane forum
                      musisz określić, jakie funkcje będzie pełniła Twoja      Element           Przykład
                      aplikacja. Być może będziesz musiał w tym celu           username         janek
                      porozmawiać z klientem lub samodzielnie zastanowić       password         haslo
                      się nad tym zagadnieniem. W każdym razie struktura       actual name      Jan Kowalski
                      bazy danych zależy od sposobu, w jaki aplikacja będzie
                                                                               user email       jank@example.com
                      odwoływała się do zgromadzonych w niej informacji.
                                                                               forum            MySQL
                      Na tym etapie będziesz więc potrzebował raczej kartki
                                                                               message subject Pytanie na temat normalizacji
                      i ołówka niż MySQL-a. Oczywiście, w ten sposób
                                                                               message body     Nie rozumiem jednej rzeczy. Dla drugiej
                      projektuje się wszystkie relacyjne bazy danych,
                                                                                                postaci normalnej (2NF) podano...
                      nie tylko te działające w systemie MySQL.
                                                                               message date     2 lutego 2008 12:20


                      176
Zaawansowany SQL i MySQL


Klucze                                              Baza danych forum składa się w zasadzie tylko z jednej
                                                    prostej tabeli (tabela 6.1), ale zanim rozpocznę proces
W rozdziale 4., „Wprowadzenie do MySQL-a”, normalizacji, chcę utworzyć w niej przynajmniej jeden
wspominałem już, że klucze są integralną częścią klucz główny (klucze obce pojawią się w następnych
znormalizowanych baz danych. Spotkasz się           krokach).
z dwoma rodzajami kluczy, głównymi i obcymi.
Klucz główny to unikatowy identyfikator, który Aby przypisać klucz główny:
podlega pewnym ściśle określonym regułom.
Musi on:                                             1. Poszukaj pól, które spełniają wszystkie trzy warunki
                                                        określone dla kluczy głównych.
    Zawsze mieć jakąś wartość (inną niż NULL).
                                                        W naszym przykładzie (tabela 6.1) żadna z kolumn
    Mieć stałą wartość (taką, która nigdy nie ulega     nie spełnia kryteriów klucza głównego. Nazwa
    zmianie).                                           użytkownika i adres e-mail są unikalne dla każdego
    Mieć inną wartość dla każdego rekordu               użytkownika forum, ale nie dla każdego rekordu
    w tabeli.                                           bazy danych (ten sam użytkownik może umieszczać
                                                        wiele wiadomości na forum). Również ten sam
Najlepszym, z życia wziętym przykładem klucza           temat wiadomości może występować wiele razy.
głównego jest numer ubezpieczenia społecznego           Tekst wiadomości będzie prawdopodobnie zawsze
przydzielany obywatelom USA. Każdy ma tam               unikalny, ale może się zmieniać na skutek
własny, niezmienny, unikatowy numer polisy.             późniejszych poprawek, tym samym naruszając
Ułatwia to identyfikowanie osób. Wkrótce                jedno z kryteriów wyboru klucza głównego.
przekonasz się, że wielokrotnie sam będziesz
tworzył we wszystkich tabelach klucze główne.        2. Jeżeli nie istnieje żaden logiczny kandydat na klucz
Jest to po prostu dobra praktyka projektowa.            główny — wprowadź go! (tabela 6.2).




                                                                                                                   Projekt bazy danych
Drugi rodzaj kluczy stanowią klucze obce.                      Sytuacja, w której musisz sam utworzyć klucz
Reprezentują one w tabeli B klucze główne                      główny, ponieważ żadne z istniejących pól nie
tabeli A. Jeżeli masz na przykład bazę danych                  nadaje się do pełnienia tej roli, występuje dość
filmy, w której występują tabele film i reżyser,               często. W tym konkretnym przykładzie utworzę
to klucz główny tabeli reżyser będzie pełnił                   pole message ID.
rolę klucza obcego w tabeli film. Już niedługo
zobaczysz, jak to wszystko działa w praktyce.                Wskazówki
                                                               Stosuję się do reguły, w myśl której w nazwach
Tabela 6.2. Dodałem do tabeli klucz główny, dzięki czemu       kluczy głównych powinna wystąpić przynajmniej
będę mógł łatwo odwoływać się do rekordów                      część nazwy tabeli (np. message) i przyrostek id.
 Baza danych forum                                             Niektórzy projektanci dodają również skrót pk
                                                               (ang. primary key — klucz główny).
 Element           Przykład
 message ID        1                                           MySQL zezwala na stosowanie w każdej tabeli
 username          janek                                       tylko jednego klucza głównego, choć możesz oprzeć
 password          haslo                                       go na kilku kolumnach (oznacza to, że kombinacja
 actual name       Jan Kowalski                                tych kolumn musi być unikatowa).
 user email        jank@example.com                            Najlepiej byłoby, gdyby Twój klucz główny
 forum             MySQL                                       był zawsze liczbą całkowitą, ponieważ pozwala
 message subject Pytanie na temat normalizacji                 to MySQL-owi osiągnąć najwyższą możliwą
 message body      Nie rozumiem jednej rzeczy. Dla drugiej     wydajność.
                   postaci normalnej (2NF) podano...
 message date      2 lutego 2008 12:20



                                                                                                             177
Rozdział 6.


                      Zależności                                             Wskazówki
                      Mówiąc o zależnościach w bazach danych mam                Modelowanie baz danych rządzi się
                      na myśli to, w jaki sposób dane z jednej tabeli są        pewnymi regułami. Istnieje określona
                      powiązane z danymi występującymi w drugiej.               konwencja reprezentowania struktury
                      Zależności między dwiema tabelami mogą                    bazy (zostanie ona tutaj zachowana).
                      przybierać postać jeden do jednego, jeden do wielu        Na rysunku 6.1 pokazałem symbole trzech
                      lub wiele do wielu. (Dwie tabele tej samej bazy           rodzajów zależności.
                      danych mogą być również wcale niepowiązane).              Proces projektowania bazy danych prowadzi
                      O zależności „jeden do jednego” mówimy wtedy,             do powstania diagramu zależności między
                      gdy jeden i tylko jeden element tabeli A odnosi się       encjami (ERD), na którym występują
                      do jednego i tylko jednego elementu tabeli B              prostokąty reprezentujące tabele oraz
                      (np. każdy mieszkaniec USA ma tylko jeden numer           symbole z rysunku 6.1.
                      ubezpieczenia społecznego, a każdy numer polisy           Istnieje wiele programów służących
                      jest przyporządkowany tylko do jednego obywatela.         do tworzenia schematów baz danych.
                      Nikt nie może mieć dwóch polis, podobnie jak              Jednym z nich jest MySQL Workbench
                      żaden numer ubezpieczenia nie może odnosić się            (www.mysql.com).
                      do dwóch osób).
                                                                                Termin „relacyjny” w określeniu „system
                      Zależność „jeden do wielu” występuje wtedy,               zarządzania relacyjnymi bazami danych”
                      gdy jakiś element tabeli A może odnosić się do kilku      odnosi się do tabel, które nazywa się
                      różnych elementów tabeli B. Na przykład,                  relacjami.
                      określenia mężczyzna i kobieta mogą być używane
                      w odniesieniu do wielu osób, ale każdy człowiek
Projekt bazy danych




                      może mieć tylko jedną płeć. Jest to najczęściej
                      występująca zależność między tabelami
                      w znormalizowanych bazach danych.
                      Istnieje też zależność „wiele do wielu”, w której
                      kilka elementów tabeli A może odnosić się do kilku
                      elementów tabeli B. Na przykład rekord płyta
                      może zawierać piosenki wykonywane przez różnych
                      artystów, a każdy artysta może mieć na swoim
                      koncie kilka płyt. W swoich projektach powinieneś
                      unikać tego typu zależności, ponieważ prowadzą one
                      do problemów ze spójnością danych i sprzyjają ich      Rysunek 6.1. Pokazane tu symbole często spotyka
                      powielaniu. Zamiast zależności „wiele do wielu”        się na diagramach strukturalnych. Opisują one
                      stworzysz tabelę pośrednią, dzięki której zależność    zależności występujące między tabelami
                      „wiele do wielu” zostanie rozbita na dwie zależności
                      „jeden do wielu”.
                      Temat zależności jest w pewien sposób związany
                      z zagadnieniem kluczy, ponieważ klucze
                      zdefiniowane w jednej tabeli odwołują się zazwyczaj
                      do pól występujących w innych tabelach.



                      178
Zaawansowany SQL i MySQL


Pierwsza postać normalna                      Na przykład tabela zawierająca pole, w którym
                                              można umieścić kilka numerów telefonów (domowy,
Jak już powiedziałem wcześniej, normalizacja komórkowy, numer faksu itd.) nie jest zgodna
bazy danych jest procesem dostosowywania z pierwszą postacią normalną, ponieważ w jednej
struktury bazy danych do kilku postaci.       kolumnie może się znaleźć więcej niż jedna wartość.
Dostosowywanie to musi być precyzyjne         Jeśli chodzi o drugi warunek, to tabela film
i odbywać się w określonej kolejności.        zawierająca kolumny aktor1, aktor2, aktor3 i tak
Mówimy, że baza danych jest pierwszej postaci dalej, nie będzie w pierwszej postaci normalnej,
normalnej (1NF), jeżeli:                      ponieważ powtarzające się kolumny zawierają
                                              ten sam rodzaj informacji.
    Każda kolumna zawiera tylko jedną wartość
    (czyli jest atomowa lub niepodzielna).    Proces normalizacji rozpocznę od sprawdzenia,
                                              czy aktualna struktura bazy (tabela 6.2) jest zgodna
    Żadna tabela nie ma powtarzających się z 1NF. Kolumny, które nie są atomowe, zostaną
    kolumn dla danych pozostających w pewnej rozbite na wiele kolumn. Jeśli tabela posiada
    zależności.                               powtarzające się, podobne kolumny, to zostaną
                                              one przekształcone w osobną tabelę.

                                                    Aby uczynić bazę zgodną z 1NF:
                                                     1. Zidentyfikuj pole, które może zawierać kilka
                                                       informacji naraz.
                                                       Gdy spojrzysz jeszcze raz na tabelę 6.2,
                                                       zobaczysz, że jedno z pól nie jest zgodne




                                                                                                         Projekt bazy danych
                                                       z 1NF: actual name. Zawiera ono zarówno
                                                       imię jak i nazwisko użytkownika.
                                                       Pole message date (data dodania do bazy)
                                                       przechowuje, co prawda, dzień, miesiąc i rok,
                                                       ale raczej nie będzie nas interesować taki
                                                       poziom szczegółowości i potraktujemy
Tabela 6.3. Tabela z atomowymi kolumnami
                                                       przechowywaną przez nie wartość jako
Baza danych forum                                      niepodzielną. Zresztą pod koniec poprzedniego
Element             Przykład                           rozdziału pokazałem, że MySQL potrafi
message ID          1                                  doskonale obsługiwać dane reprezentujące
username            janek                              daty i czas za pomocą typu DATETIME.
password            haslo                              Gdyby tabela zawierała na przykład jedną,
first name          Jan                                wspólną kolumnę dla imienia i nazwiska zamiast
last name           Kowalski                           dwóch osobnych albo przechowywała wiele
user email          jank@example.com                   numerów telefonów (stacjonarny, komórkowy,
forum               MySQL                              domowy, służbowy) w jednej kolumnie,
message subject     Pytanie na temat normalizacji      to kolumny te również należałoby rozbić.
message body        Nie rozumiem jednej rzeczy.
                    Dla drugiej postaci normalnej
                                                     2. Rozbij wszystkie pola odszukane w kroku 1.
                    (2NF) podano...                    na kilka mniejszych, niepodzielnych pól
message date        2 lutego 2008 12:20                (tabela 6.3).


                                                                                                   179
Rozdział 6.


                         Aby poradzić sobie z tym problemem, utwórz        Wskazówki
                         osobne pola first name i last name, które będą
                                                                                Dostosowanie tabeli do 1NF wymaga
                         zawierać tylko jedną wartość.
                                                                                analizy tabeli w poziomie. Wszystkie
                       3. Przekształć każdą grupę powtarzających się            kolumny jednego rekordu przeglądamy
                         kolumn w osobną tabelę.                                pod kątem występowania w nich danych,
                                                                                które nie są atomowe oraz występowania
                         Problem ten nie występuje w bazie danych
                                                                                powtarzających się, podobnych danych.
                         forum. Zademonstruję go zatem na przykładzie
                         przedstawionym w tabeli 6.4. Powtarzające się          Postacie normalne opisane są w różnych
                         kolumny zawierające informacje o aktorach              źródłach w różny sposób, często z użyciem
                         powodują dwa problemy. Po pierwsze,                    bardziej technicznego żargonu.
                         dla każdego filmu można podać tylko                    Najważniejszy jest jednak sens i końcowy
                         ograniczoną liczbę aktorów. Nawet jeśli                rezultat procesu normalizacji, a nie
                         wprowadzimy kolumny aktor 1 aż do aktor 100,           słownictwo zastosowane do jego opisu.
                         to ograniczeniem będzie stu aktorów. Po drugie,
                         każdy rekord, który nie zawiera maksymalnej       Tabela 6.4. Tabela film nie jest zgodna z 1NF
                         liczby aktorów, będzie mieć wartości NULL         z dwóch powodów. Po pierwsze, zawiera
                         w nadmiarowych kolumnach. W schemacie             powtarzające się kolumny podobnych danych
                         bazy danych powinniśmy unikać kolumn              (aktor1 itd.). Po drugie, kolumny aktor i reżyser
                         zawierających wartości NULL. Dodatkowym           nie zawierają wartości atomowych
                         problemem jest również to, że kolumny             Tabela film
                         zawierające informacje o reżyserze i aktorach     Kolumna                 Wartość
                         nie są atomowe.                                   film ID                 976
Projekt bazy danych




                         Aby rozwiązać problemy występujące w tabeli       tytuł filmu             Casablanca
                         film, utworzę dodatkową tabelę (tabela 6.5).      rok produkcji           1943
                         Każdy jej rekord zawiera informacje o jednym      reżyser                 Michael Curtiz
                         autorze, co rozwiązuje problemy opisane           aktor1                  Humphrey Bogart
                         powyżej. Także nazwiska i imiona aktorów są       aktor2                  Ingrid Bergman
                         teraz przechowywane jako wartości atomowe.        aktor3                  Peter Lorre
                         Zwróć również uwagę, że do nowej tabeli
                         dodałem kolumnę indeksu głównego. Zasada,         Tabela 6.5. Aby tabela film (tabela 6.4) była zgodna
                         że każda tabela posiada klucz główny, wynika      z 1NF, powiążę aktorów z filmami za pomocą tabeli
                         wprost z pierwszej postaci normalnej.             film-aktor
                       4. Upewnij się, że wszystkie nowe pola utworzone    Tabela film-aktor
                         w kroku 2. i 3. są zgodne z 1NF.                  ID    Film              Imię aktora   Nazwisko aktora
                                                                           1     Casablanca        Humphrey      Bogart
                                                                           2     Casablanca        Ingrid        Bergman
                                                                           3     Casablanca        Peter         Lorre
                                                                           4     Sokół maltański   Humphrey      Bogart
                                                                           5     Sokół maltański   Peter         Lorre




                      180
Zaawansowany SQL i MySQL


                                                  Druga postać normalna
                                                   Każda baza, która ma spełniać drugą postać
                                                   normalną (2NF), musi być najpierw zgodna z 1NF
                                                   (proces normalizacji trzeba przeprowadzać
                                                   we właściwej kolejności). Następnie wszystkie
                                                   kolumny, które nie zawierają kluczy (kluczy obcych),
                                                   muszą być powiązane zależnością z kluczem
                                                   głównym. Kolumny, które naruszają ten warunek,
Rysunek 6.2. Aby baza danych o filmach była zgodna łatwo zidentyfikować po tym, że zawierają wartości
z 2NF, potrzebne są cztery tabele. Reżyserzy są
                                                   niebędące kluczami i powtarzające się w różnych
reprezentowani w tabeli film za pomocą klucza
                                                   rekordach. Wartości te muszą zostać umieszczone
reżyser ID; filmy są reprezentowane w tabeli
film-aktor za pomocą klucza film ID; aktorzy są    w osobnej tabeli i być powiązane z tabelą wyjściową
reprezentowani w tabeli film-aktor za pomocą       za pomocą klucza.
klucza aktor ID                                   Przykładem może być fikcyjna tabela film
                                                  (tabela 6.4), która zawierałaby ponad dwadzieścia
                                                  razy nazwisko Martina Scorsese jako reżysera
                                                  różnych filmów. Sytuacja taka jest niezgodna z drugą
                                                  postacią normalną, ponieważ kolumna zawierająca
                                                  informację o reżyserze nie jest kluczem i nie jest
                                                  powiązana zależnością z kluczem głównym (film ID).
                                                  Rozwiązanie polega na utworzeniu osobnej tabeli
                                                  reżyserzy wyposażonej we własny klucz główny,




                                                                                                          Projekt bazy danych
                                                  który wystąpiłby jako klucz obcy w tabeli film,
                                                  tworząc w ten sposób powiązanie obu tabel.
                                                  Patrząc na tabelę 6.5, można dostrzec dwa kolejne
                                                  naruszenia drugiej 2NF — ani tytuły filmów,
                                                  ani nazwiska aktorów nie są powiązane z kluczem
                                                  głównym tabeli. Zatem baza danych o filmach
                                                  w najprostszej postaci wymaga czterech tabel
                                                  (rysunek 6.2). W ten sposób informacje o każdym
                                                  filmie, aktorze i reżyserze są przechowywane tylko
                                                  jeden raz, a każda kolumna niebędąca kluczem
                                                  jest zależna od klucza głównego danej tabeli.
                                                  W zasadzie proces normalizacji można by określić
                                                  jako tworzenie coraz większej liczby tabel, tak
                                                  aby całkowicie wyeliminować możliwość powielenia
                                                  jakichkolwiek danych.




                                                                                                    181
Rozdział 6.


                      Aby uczynić bazę zgodną z 2NF:
                       1. Zidentyfikuj kolumny, które nie są kluczami
                            i które nie są powiązane z kluczem głównym.
                            Przyglądając się tabeli 6.3 zauważysz, że żadne
                            z pól username, first name, last name, email
                            i forum nie są kluczami (jedyną kolumną będącą
                            kluczem jest na razie message ID) i żadne z nich
                            nie jest powiązane zależnością z message ID.
                            Natomiast message subject, body i date również
                                                                                 Rysunek 6.3. Aby baza danych forum była zgodna
                            nie są kluczami, ale ich wartości zależą od klucza   z 2NF, potrzebne są trzy tabele
                            message ID.

                       2. Utwórz odpowiednie tabele (patrz rysunek 6.3).
                            Najlogiczniejsza modyfikacja istniejącej struktury
                            polega na utworzeniu trzech tabel: users, forums
                            i messages.
                            Na diagramie bazy danych każda tabela została
                            przeze mnie oznaczona prostokątem. Jej nazwa
                            pełni rolę nagłówka, pod którym wymienione
                            są wszystkie kolumny (atrybuty) tabeli.
                       3. Przypisz lub utwórz nowe klucze główne
Projekt bazy danych




                            (rysunek 6.4).
                                                                                 Rysunek 6.4. Każda tabela powinna mieć własny
                            Posługując się technikami opisanymi wcześniej        klucz główny
                            w tym rozdziale, upewnij się, że każda nowa
                            tabela ma zdefiniowany klucz główny. W tabeli
                            users stworzyłem klucz user ID, a w tabeli
                            forums klucz forum ID. Ponieważ pole username
                            w tabeli users oraz pole name w tabeli forums
                            muszą być unikalne dla każdego rekordu i zawsze
                            mieć wartość, to mógłbyś użyć ich jako kluczy
                            głównych. Oznaczałoby to jednak, że wartości
                            tych pól nie mogą się zmieniać (zgodnie
                            z jednym z kryteriów wyboru klucza głównego).
                            Użycie kluczy tekstowych zamiast numerycznych
                            powodowałoby również nieco wolniejsze
                            działanie bazy danych.




                      182
Zaawansowany SQL i MySQL


                                                    4. Utwórz pomocnicze klucze obce, które połączą
                                                      tabele zależnościami (rysunek 6.5).
                                                      Ostatni krok na drodze do zgodności z 2NF
                                                      polega na dodaniu kluczy obcych, które określą
                                                      powiązania między tabelami. Pamiętaj, że to,
                                                      co w jednej tabeli jest kluczem głównym,
                                                      w drugiej najprawdopodobniej będzie kluczem
                                                      obcym.
                                                      W naszym przykładzie kolumna user ID z tabeli
                                                      users łączy się z kolumną user ID z tabeli
Rysunek 6.5. Aby zdefiniować zależność między         messages. Dlatego też tabela users pozostaje
tymi trzema tabelami, dodałem do tabeli messages      w zależności „jeden do wielu” z tabelą messages
dwa klucze obce, z których każdy łączy ją z jedną     (każdy użytkownik może umieścić na forum
z pozostałych dwóch tabel                             wiele wiadomości, ale każda wiadomość może
                                                      mieć tylko jednego autora).
                                                      Połączone zostały również dwie kolumny
                                                      forum ID, tworząc w ten sposób zależność „jeden
                                                      do wielu” pomiędzy tabelami messages i forums
                                                      (każda wiadomość może należeć tylko do jednego
                                                      forum, ale dane forum może zawierać wiele
                                                      wiadomości).




                                                                                                         Projekt bazy danych
Wskazówki
   Inny sposób sprawdzenia, czy tabele                W prawidłowo znormalizowanej bazie danych
   spełniają drugą postać normalną, polega            w jednej tabeli nie mają prawa pojawić się
   na przyjrzeniu się powiązaniom tabel.              dwa takie same rekordy (dwa lub więcej
   Idealna sytuacja polega na występowaniu            rekordów, w których wartości występujące
   samych zależności „jeden do wielu”.                w poszczególnych kolumnach są identyczne).
   Tabele podlegające zależnościom „wiele
                                                      Aby łatwiej przyswoić sobie proces normalizacji,
   do wielu” mogą wymagać restrukturyzacji.
                                                      zapamiętaj, że pierwsza postać normalna
   Jeśli przyjrzymy się jeszcze raz rysunkowi         wiąże się z analizą tabeli w poziomie, podczas
   6.2, możemy zauważyć, że tabela film-aktor         gdy druga postać normalna powstaje na skutek
   spełnia funkcję tabeli pośredniczącej.             analizy w pionie (poszukiwania wartości
   Pozwala ona zamienić zależność „wiele              powtarzających się w wielu rekordach).
   do wielu” zachodzącą pomiędzy filmami
   i aktorami na dwie zależności „jeden
   do wielu”. Tabele pośredniczące łatwo
   rozpoznać po tym, że wszystkie ich kolumny
   są kluczami obcymi. W tym przypadku
   kolumna odgrywająca rolę klucza głównego
   nie jest potrzebna, ponieważ kluczem
   głównym może być kombinacja obu
   kolumn tabeli.

                                                                                                   183
Rozdział 6.


                      Trzecia postać normalna                                 Aby uczynić bazę zgodną z 3NF:
                      Mówimy, że baza danych spełnia trzecią postać            1. Zidentyfikuj wszystkie pola, które nie są
                      normalną (3NF), jeżeli jest ona zgodna z 2NF,              bezpośrednio powiązane z kluczem
                      a każda kolumna, która nie jest kluczem, jest zależna      głównym.
                      od klucza głównego. Jeżeli prawidłowo przeszedłeś          Jak już wspomniałem, na tym etapie
                      przez pierwsze dwa etapy normalizacji,                     poszukujemy kolumn, które powiązane są
                      prawdopodobnie dostosowanie bazy danych do 3NF             między sobą zależnościami (tak jak miasto
                      nie będzie już wymagać żadnych zmian. W moim               i stan) zamiast z kluczem głównym.
                      przykładzie (patrz rysunek 6.5) również nie ma             W bazie danych forum nie występowały
                      problemów, które należałoby rozwiązać, aby baza            takie zależności. Przyjrzyjmy się tabeli
                      była zgodna z trzecią postacią normalną. Dlatego           messages. Każda wartość pola subject
                      też przedstawię je omawiając hipotetyczną sytuację.        jest specyficzna dla danego message ID,
                      Weźmy na przykład pojedynczą tabelę                        każda wartość pola body jest specyficzna
                      przechowującą informacje o zarejestrowanych                dla wybranego message ID itd.
                      klientach: imię, nazwisko, e-mail, numer telefonu,       2. Utwórz odpowiednie tabele.
                      adres pocztowy itp. Tabela taka nie jest zgodna            Jeśli w punkcie 1. udało się odnaleźć
                      z 3NF, ponieważ wiele kolumn nie będzie zależnych          problematyczne kolumny, takie jak
                      od klucza głównego. Nazwa ulicy będzie zależeć             na przykład miasto i stan, to tworzymy
                      od miasta, a miasto od stanu. Również kod pocztowy         dla nich osobne tabele cities i states.
                      nie będzie zależeć od tego, jaką osobę opisuje
                                                                               3. Przypisz lub utwórz nowe klucze główne.
                      rekord. Aby znormalizować taką bazę danych,
                      powinno się stworzyć osobną tabelę reprezentującą          Każda tabela musi mieć klucz główny,
                                                                                 wobec czego do nowych tabel dodaję
Projekt bazy danych




                      państwa, osobną reprezentującą miasta (połączoną
                      kluczem obcym z tabelą państw) i jeszcze inną              kolumny city ID i state ID.
                      dla kodów. Wszystkie te tabele byłyby połączone         4. Utwórz pomocnicze klucze obce, definiując
                      z tabelą opisującą klientów.                               tym samym zależności (rysunek 6.6).
                      Jeśli takie rozwiązanie wydaje Ci się przesadą,            Na zakończenie dodałem do tabeli Cities
                      to masz rację. Wyższy stopień normalizacji często          klucz obcy State ID oraz klucz obcy City ID
                      nie jest konieczny. Chociaż powinno się dążyć              do tabeli Clients. W efekcie uzyskałem
                                                                                 połączenie rekordu klienta nie tylko
                      do jak najpełniejszej normalizacji, to czasami warto
                                                                                 z informacją o mieście, w którym jest
                      ją poświęcić na rzecz prostoty. (patrz ramka
                                                                                 zameldowany, ale również o stanie.
                      „Rezygnacja z normalizacji”). W praktyce stopień
                      normalizacji zależy od potrzeb konkretnej aplikacji
                      i szczegółów bazy danych.
                      Jak już wspomniałem, nasz przykład bazy forum
                      nie wymaga dalszej normalizacji (jest już zgodny
                      z 3NF) i dlatego proces dostosowywania do trzeciej
                      postaci normalnej przedstawię właśnie na przykładzie
                      omówionej wyżej bazy danych o klientach.


                                                                              Rysunek 6.6. Uproszczona wersja hipotetycznej
                                                                              bazy clients będzie zawierać dwie nowe tabele
                                                                              przechowujące informacje o miastach i stanach

                      184
Zaawansowany SQL i MySQL


                                                  Wskazówka
                                                    W praktyce nie normalizowałbym tabeli Clients
                                                    aż do takiego stopnia. Gdybym pozostawił
                                                    pola opisujące miasto i stan w tabeli Clients,
                                                    to najgorszą rzeczą, jaka mogłaby się zdarzyć,
                                                    byłaby zmiana nazwy miasta i związana z tym
                                                    konieczność aktualizacji rekordów wszystkich
                                                    klientów będących jego mieszkańcami.
                                                    W rzeczywistości jednak sytuacja taka zdarza
                                                    się bardzo rzadko.
                                                    Mimo istnienia zasad normalizacji baz danych
                                                    dwóch różnych projektantów może dokonać
                                                    normalizacji tej samej bazy w nieco inny sposób.
                                                    Projektowanie baz danych pozostawia pewien
                                                    margines dla indywidualnych preferencji
     Rezygnacja z normalizacji                      i interpretacji. Najważniejsze jest,
Choć spełnienie trzeciej postaci normalnej          by zaprojektowana baza danych nie naruszała
jest korzystne, nie oznacza to jeszcze,             postaci normalnej, gdyż prędzej czy później
że masz normalizować każdą bazę danych,             doprowadzi to do pojawienia się poważnych
z którą pracujesz. Jednocześnie                     problemów.
powinieneś uzmysłowić sobie, że odejście
od sprawdzonych metod może mieć




                                                                                                       Projekt bazy danych
w perspektywie dłuższego czasu
katastrofalne skutki.
Z normalizacji rezygnuje się zazwyczaj
z dwóch powodów — ze względu
na wydajność i dla wygody. Dużo łatwiej
jest ogarnąć mniejszą liczbę tabel, a poza
tym — łatwiej się nimi zarządza. Ze względu
na liczbę powiązań między tabelami,
uaktualnianie, odczytywanie i modyfikowanie
danych w znormalizowanych bazach danych
trwa z reguły dłużej. Krótko mówiąc,
normalizacja jest poświęceniem prostoty
i szybkości na rzecz spójności i skalowalności.
Należy jednak pamiętać, że istnieje znacznie
więcej sposobów na przyspieszenie bazy
danych niż na odzyskanie informacji
utraconych na skutek przechowywania ich
w źle zaprojektowanej bazie.
W miarę nabywania doświadczenia będziesz
potrafił coraz lepiej modelować bazy danych,
ale mimo wszystko staraj się trzymać
po stronie normalizacji.


                                                                                                 185
Rozdział 6.


                      Tworzenie bazy danych                                  2. Utwórz bazę danych forum (rysunek 6.7).
                      Aby zakończyć projekt bazy danych, musimy                    CREATE DATABASE forum;
                      wykonać trzy ostatnie kroki:                                 USE forum;

                       1. Sprawdzić, czy w bazie znajdą się wszystkie          Możliwe, że Twoja konfiguracja nie pozwala
                         potrzebne informacje.                                 na tworzenie nowych baz danych. W takiej
                                                                               sytuacji po prostu wykorzystaj jakąś już
                       2. Zidentyfikować typy kolumn.                          istniejącą bazę i dodawaj do niej kolejne
                       3. Nazwać wszystkie elementy bazy danych.               tabele.

                      Ostateczny projekt bazy danych został                Tabela 6.6. Ostateczny projekt bazy forum
                      przedstawiony w tabeli 6.6. W porównaniu             wraz z typami kolumn
                      do rysunku 6.5 została dodana jeszcze jedna           forum
                      kolumna. Ponieważ wiadomość umieszczana
                                                                            Nazwa kolumny Tabela       Typ kolumny
                      na forum może być odpowiedzią na inną wiadomość,
                      musimy jakoś reprezentować tę zależność w bazie.      forum_id         forums    TINYINT

                      Rozwiązanie polega na dodaniu kolumny parent_id       name             forums    VARCHAR(60)
                      w tabeli messages. Jeśli wiadomość jest odpowiedzią, message_id        messages INT
                      to jej pole parent_id będzie zawierać wartość pola    forum_id         messages TINYINT
                      message_id oryginalnej wiadomości (czyli message_id   parent_id        messages INT
                      spełnia funkcję klucza obcego w tej samej tabeli).    user_id          messages MEDIUMINT
                      Jeśli pole parent_id ma wartość równą 0, oznacza      subject          messages VARCHAR(100)
                      to, że wiadomość stanowi początek nowego wątku,       body             messages LONGTEXT
                      czyli nie jest odpowiedzią na żadną inną wiadomość. date_entered       messages TIMESTAMP
Projekt bazy danych




                                                                            user_id           users     MEDIUMINT
                      Jeśli wprowadzasz jakiekolwiek zmiany w strukturze
                                                                            username          users     VARCHAR(30)
                      tabel, powinieneś ponownie sprawdzić, czy spełniają
                                                                            pass              users     CHAR(40)
                      one wszystkie postacie normalne, aby mieć pewność,
                                                                            first_name        users     VARCHAR(20)
                      że baza danych jest nadal znormalizowana.
                                                                            last_name         users     VARCHAR(40)
                      Zagadnienie nazw tabel i kolumn oraz wyboru typów     email             users     VARCHAR(80)
                      kolumn omówiłem już w rozdziale 4.
                      Gdy schemat jest gotowy, możesz utworzyć
                      odpowiadającą mu bazę danych MySQL-a
                      za pomocą poleceń omówionych w rozdziale 5.,
                      „Wprowadzenie do SQL”.

                      Aby utworzyć bazę danych:
                       1. Użyj wybranego klienta do dostępu do serwera      Rysunek 6.7. Najpierw musisz utworzyć
                         MySQL-a.                                           i wybrać bazę danych

                         Podobnie jak w poprzednim rozdziale,
                         we wszystkich przykładach będziemy posługiwali
                         się monitorem (klientem) mysqla. Oczywiście
                         możesz też śmiało korzystać z phpMyAdmina
                         i innych narzędzi.


                      186
Zaawansowany SQL i MySQL


 3. Utwórz tabelę forums (rysunek 6.8).         Tabela ta zawiera tylko dwie kolumny
     CREATE TABLE forums (                      (sytuacja taka ma często miejsce w przypadku
        forum_id TINYINT UNSIGNED               znormalizowanych baz danych). Ponieważ nie
          NOT NULL AUTO_INCREMENT,              spodziewam się, że tabela ta będzie zawierać
        name VARCHAR(60) NOT NULL,              dużą liczbę rekordów, klucz główny otrzymał
        PRIMARY KEY (forum_id)
     );                                         typ TINYINT. Jeśli chcesz, by baza zawierała
                                                również opis każdego forum, możesz dodać
   Kolejność, w jakiej tworzysz tabele,         do tej tabeli kolumnę typu VARCHAR(255).
   nie ma oczywiście znaczenia. Ja zacznę
   od forums. Pamiętaj, że zawsze możesz      4. Utwórz tabelę messages (rysunek 6.9).
   rozpisać polecenie SQL w kilku wierszach       CREATE TABLE messages (
   na ekranie, jeżeli tylko będzie Ci tak            message_id INT UNSIGNED
                                                       NOT NULL AUTO_INCREMENT,
   wygodniej.
                                                     forum_id TINYINT UNSIGNED
                                                       NOT NULL,
                                                     parent_id INT UNSIGNED NOT NULL,
                                                     user_id MEDIUMINT UNSIGNED
                                                       NOT NULL,
                                                     subject VARCHAR(100) NOT NULL,
                                                     body LONGTEXT NOT NULL,
                                                     date_entered TIMESTAMP NOT NULL,
                                                     PRIMARY KEY (message_id)
                                                  );

                                                W tym przypadku klucz główny musi być
                                                zdecydowanie bardziej pojemny, ponieważ




                                                                                                Projekt bazy danych
                                                spodziewam się, że tabela ta będzie zawierać
                                                bardzo dużo rekordów. Trzy kolumny będące
                                                kluczami obcymi — forum_id, parent_id
                                                i user_id — będą mieć taki sam rozmiar i typ
Rysunek 6.8. Utwórz pierwszą tabelę             jak ich odpowiedniki będące kluczami
                                                głównymi w innych tabelach. Pole subject
                                                zostało ograniczone do 100 znaków, a pole
                                                body może zawierać znaczną ilość tekstu. Pole
                                                date_entered otrzymało typ TIMESTAMP. Będzie
                                                ono przechowywać datę i czas dodania rekordu.
                                                Jego wartość zostanie automatycznie
                                                zaktualizowana (bieżącą datą i czasem)
                                                w momencie wstawienia rekordu (właśnie
                                                w ten sposób zachowuje się typ TIMESTAMP).

Rysunek 6.9. Utwórz drugą tabelę




                                                                                          187
Rozdział 6.


                       5. Utwórz tabelę users (rysunek 6.10).                  6. Jeśli chcesz, możesz upewnić się, że baza
                              CREATE TABLE users (                                danych ma taką strukturę jak powinna
                                 user_id MEDIUMINT UNSIGNED                       (rysunek 6.11).
                                   NOT NULL AUTO_INCREMENT,
                                                                                    SHOW   TABLES;
                                 username VARCHAR(30) NOT NULL,
                                                                                    SHOW   COLUMNS FROM forums;
                                 pass CHAR(40) NOT NULL,
                                                                                    SHOW   COLUMNS FROM messages;
                                 first_name VARCHAR(20) NOT NULL,
                                                                                    SHOW   COLUMNS FROM users;
                                 last_name VARCHAR(40) NOT NULL,
                                 email VARCHAR(80) NOT NULL,                      Ten krok jest opcjonalny, ponieważ MySQL
                                 PRIMARY KEY (user_id)
                              );
                                                                                  i tak wyświetla informacje o pomyślnym
                                                                                  wykonaniu każdego wprowadzanego
                            Większość kolumn tej tabeli wykorzystuje              polecenia. Warto jednak przypomnieć
                            definicje znane z tabeli users bazy sitename          sobie strukturę bazy danych.
                            używanej w poprzednich dwóch rozdziałach.
                            Kolumna pass jest typu CHAR(40), ponieważ         Wskazówka
                            dla haseł będę stosować funkcję SHA1(), która
                                                                                  W przypadku połączenia klucz
                            zwraca zawsze łańcuch o długości 40 znaków
                                                                                  główny-klucz obcy (na przykład forum_id
                            (patrz rozdział 5.).
                                                                                  tabeli forum z forum_id tabeli messages),
                                                                                  obie kolumny muszą być tego samego typu
                                                                                  (w naszym przykładzie: TINYINT UNSIGNED
                                                                                  NOT NULL).
Projekt bazy danych




                      Rysunek 6.10. Trzecia i ostatnia tabela w bazie Rysunek 6.11. Sprawdź strukturę bazy za pomocą polecenia
                                                                      SHOW


                      188
Zaawansowany SQL i MySQL


Wypełnianie bazy danych                             Aby zapełnić bazę danymi:
W rozdziale 15. napiszemy w PHP interfejs            1. Dodaj kilka nowych rekordów do tabeli forums
WWW dla bazy forums. Będzie on dostarczać              (rysunek 6.12).
standardowego sposobu wypełniania bazy                   INSERT INTO forums (name) VALUES ('MySQL'),
danymi (poprzez rejestrowanie się                        ('PHP'), ('Programowanie'), ('HTML'),
użytkowników i umieszczanie wiadomości                   ('CSS'), ('Bazy danych');
na forum). Zanim jednak dojdziemy do tego              Ponieważ tablica messages jest zależna od
punktu, musisz się jeszcze sporo nauczyć.              wartości odczytywanych z tabel forums i users,
Dlatego na razie wypełnimy bazę danymi                 wypełnię najpierw te ostatnie. W przypadku
za pomocą klienta mysqla. Możesz wykonać               powyższego polecenia INSERT wystarczy jedynie
po kolei poniższe kroki lub skorzystać                 podać wartość kolumny name (MySQL
z gotowych poleceń SQL-a dołączonych do                automatycznie nada wartość kolumnie forum_id).
przykładów zamieszczonych na serwerze ftp.
                                                     2. Dodaj nowe rekordy do tabeli users
                                                       (rysunek 6.13).
                                                         INSERT INTO users (username, pass,
                                                         first_name, last_name, email) VALUES
                                                         ('janek', SHA1('haslo'),
                                                         'Jan', 'Kowalski', 'jank@example.com'),
                                                         ('ak', SHA1('haselko'),
                                                         'Arkadiusz', 'Kaczmarek', 'ak@example.com'),
                                                         ('GosiaM', SHA1('tajne'), 'Małgorzata',
                                                         'Malinowska', 'mm@example.com');
Rysunek 6.12. Dodawanie rekordów do tabeli forums




                                                                                                            Projekt bazy danych
                                                       Jeśli masz wątpliwości co do składni polecenia
                                                       INSERT lub zastosowania funkcji SHA1(), skorzystaj
                                                       z informacji podanych w rozdziale 5.




Rysunek 6.13. Dodawanie rekordów do tabeli users




                                                                                                     189
Rozdział 6.


                       3. Wstaw nowe rekordy do tabeli messages                      Sprawę dodatkowo komplikuje kolumna
                         (patrz rysunek 6.14).                                       parent_id. Musi ona zawierać wartość
                            SELECT * FROM forums;                                    message_id tej wiadomości, na którą
                            SELECT user_id, username FROM users;                     odpowiedź stanowi nowa wiadomość.
                            INSERT INTO messages (forum_id,                          Druga wiadomość umieszczona w bazie
                            parent_id, user_id, subject, body)                       danych będzie mieć message_id równy
                            VALUES
                            (1, 0, 1, 'Pytanie na temat normalizacji',               2 i wobec tego każda wiadomość stanowiąca
                              'Nie rozumiem jednej rzeczy. Dla drugiej               odpowiedź na tę wiadomość będzie musiała
                              postaci normalnej (2NF) podano...'),                   mieć wartość parent_id równą 2.
                            (1, 0, 2, 'Projekt bazy danych', 'Projektuję
                              nową bazę danych i natrafiłem na pewien                W tworzonych przez Ciebie skryptach
                              problem. Ile tabel powinna mieć moja                   PHP, wszystko to będzie wyglądało
                              baza?...'),
                            (1, 2, 1, 'Projekt bazy danych', 'Liczba
                                                                                     znacznie prościej. Muszę teraz jednak
                              tabel w Twojej bazie danych...'),                      wyłożyć Ci całą teorię, posługując się
                            (1, 3, 2, 'Projekt bazy danych', 'OK,                    terminologią języka SQL.
                              dziękuję!'),
                            (2, 0, 3, 'Błędy PHP', 'Próbuję uruchomić                Zwróć również uwagę, że nie wprowadziłem
                              skrypty z rozdziału 3. i pierwszy skrypt               wartości dla pola date_entered. MySQL
                              kalkulatora nie działa. Gdy akceptuję
                                                                                     automatycznie umieści w nim bieżącą
                              formularz...');
                                                                                     datę i czas, ponieważ jest to kolumna
                         Ponieważ dwa pola tabeli messages (forum_id                 typu TIMESTAMP.
                         oraz user _id) odwołują się do wartości
                                                                                  4. Powtórz kroki od 1. do 3., aby zapełnić
                         przechowywanych w innych tabelach,
                                                                                     bazę danymi.
                         przed wstawieniem nowych rekordów
Projekt bazy danych




                         dokonam wyboru tych wartości. Na przykład,                  We wszystkich kolejnych przykładach
                         gdy użytkownik janek utworzy nową wiadomość                 w tym rozdziale będę wykorzystywał bazę,
                         na forum MySQL-a, musisz użyć forum_id                      którą właśnie zapełniłem. Jeśli chcesz,
                         równy 1 i user_id równy 1.                                  możesz wykonać u siebie te same polecenia
                                                                                     INSERT co ja lub utworzyć swoje własne.




                      Rysunek 6.14. W przypadku znormalizowanych baz danych bardzo często spotkasz się z sytuacją,
                      w której, aby wstawić jakiś rekord do tabeli, będziesz musiał znać wartości przechowywane w innych tabelach


                      190
Zaawansowany SQL i MySQL

                                                     SELECT * FROM messages
Złączenia                                              INNER JOIN forums
                                                       ON messages.forum_id =
Ponieważ relacyjne bazy danych mają złożoną            forums.forum_id
strukturę, aby wydobyć te informacje, które            WHERE forums.name = 'MySQL'
najbardziej nas interesują, musimy czasem
                                                  Złączenie to wybiera wszystkie kolumny obu tabel,
wykonać jakieś niestandardowe zapytanie.
                                                  jeśli spełnione są dwa warunki. Po pierwsze,
Na przykład, jeśli chcesz dowiedzieć się, jakie
                                                  kolumna forums.name musi zawierać wartość
wiadomości zawiera forum MySQL-a, musisz
najpierw dowiedzieć się, jaka jest wartość        MySQL (której odpowiada wartość forum_id
forum_id dla tego forum, a następnie użyć
                                                  równa 1). Po drugie, wartość forum_id w tabeli
                                                  forums musi odpowiadać wartości forum_id
jej do pobrania wszystkich rekordów tabeli
message, które mają taką wartość forum_id.
                                                  w tabeli messages. Ze względu na sprawdzenie
Jak z tego wynika, to proste zadanie wymaga       równości dotyczące pól w różnych tabelach
wykonania dwóch zapytań. Jednak stosując          (messages.forum_id = forums.forum_id) złączenie
złączenie, możesz poradzić sobie z nim            takie nazywa się równościowym.
w jednym kroku.                                   Złączenia wewnętrzne możesz również zapisywać
Złączenie jest zapytaniem SQL-a używającym        bez stosowania klauzuli INNER JOIN:
dwóch lub więcej tabel i tworzącym wirtualną         SELECT * FROM messages, forums WHERE
tabelę wyników. W specyfikacji SQL-a                 messages.forum_id = forums.forum_id
                                                     AND forums.name = 'mySQL'
występują dwa główne typy złączeń:
wewnętrzne i zewnętrzne (oba mają szereg          Jeżeli wybierasz dane z wielu tabel i kolumn,
podtypów).                                        a w kilku tabelach występują kolumny o takiej samej
                                                  nazwie, musisz zastosować notację z kropką
Złączenie wewnętrzne zwraca wszystkie
                                                  (tabela.kolumna). W przypadku relacyjnych baz
rekordy podanych tabel, dla których zachodzi
                                                  danych robi się to praktycznie zawsze, ponieważ
dopasowanie. Na przykład, aby uzyskać




                                                                                                           Złączenia
                                                  klucz główny jednej tabeli ma taką samą nazwę
wszystkie wiadomości zamieszczone
                                                  jak obcy klucz drugiej. Jeżeli nie wskażesz
na forum MySQL, powinieneś użyć
                                                  jednoznacznie kolumny, do której się odwołujesz,
następującego złączenia wewnętrznego
                                                  zobaczysz komunikat o błędzie (rysunek 6.16).
(rysunek 6.15):




Rysunek 6.15. To złączenie zwraca kolumny obu tabel dla rekordów, dla których wartości
forum_id są równe MySQL (1)



                                                         Rysunek 6.16. Ogólne odwołanie do kolumny
                                                         występującej w kilku tabelach spowoduje
                                                         wystąpienie błędu niejednoznaczności

                                                                                                     191
Rozdział 6.


            Złączenia zewnętrzne różnią się od złączeń                  Jeżeli w warunku porównania złączenia
            wewnętrznych tym, że potrafią zwracać rekordy,              zewnętrznego bądź wewnętrznego występuje
            które nie spełniają wyrażenia warunkowego.                  kolumna o takiej samej nazwie w obu tabelach,
            Istnieją trzy podtypy złączeń zewnętrznych: left            możesz uprościć zapis zapytania, stosując
            (lewe), right (prawe) i full (pełne). Przykładem            klauzulę USING:
            pierwszego podtypu jest następujące złączenie:                 SELECT * FROM messages
              SELECT * FROM forums                                           INNER JOIN forums
              LEFT JOIN messages ON                                          USING (forum_id)
              forums.forum_id = messages.forum_id;                           WHERE forums.name = 'mySQL'
                                                                           SELECT * FROM forums
            Najważniejsze przy tego rodzaju złączeniach                      LEFT JOIN messages
            jest to, które tabele należy wymienić jako pierwsze.             USING (forum_id)
            W powyższym przykładzie w przypadku udanego                 Zanim przejdę do przykładów, jeszcze dwie
            dopasowania zwrócone zostaną wszystkie rekordy              uwagi. Po pierwsze, ponieważ składnia
            tabeli forums wraz ze wszystkimi informacjami               wymagana przy tworzeniu złączeń jest dość
            z tabeli messages. Jeśli dla danego rekordu tabeli          skomplikowana, przy ich pisaniu przydają się
            forums nie można dopasować informacji w tabeli              aliasy omówione w rozdziale 5. Po drugie,
            messages, to zamiast nich zostaną zwrócone                  ponieważ złączenia często zwracają dużo
            wartości NULL (rysunek 6.17).                               danych, to najlepiej zawsze określić, które
                                                                        kolumny nas interesują, zamiast wybierać
                                                                        wszystkie.
Złączenia




            Rysunek 6.17. To złączenie zewnętrzne zwraca więcej rekordów niż złączenie wewnętrzne, ponieważ zwraca
            wszystkie wiersze pierwszej tabeli. Zapytanie to zwraca również nazwy wszystkich forów, nawet jeśli nie zawierają
            one jeszcze żadnej wiadomości




            192
Zaawansowany SQL i MySQL


Aby wykorzystać złączenia:                        2. Pobierz temat i datę wprowadzenia każdej
                                                    wiadomości wysłanej przez użytkownika janek
 1. Pobierz nazwę forum i temat wiadomości
                                                    (rysunek 6.19).
    dla każdego rekordu tabeli messages
   (patrz rysunek 6.18).                              SELECT m.subject,
                                                        DATE_FORMAT(m.date_entered,
     SELECT f.name, m.subject                             '%M %D, %Y') AS Date
     FROM forums                                        FROM users AS u INNER JOIN
     AS f INNER JOIN messages AS m                        messages AS m
     USING (forum_id) ORDER BY f.name;                  USING (user_id)
                                                        WHERE u.username = 'janek';
   Zapytanie to zawiera złączenie wewnętrzne,
   które spowoduje w efekcie zastąpienie            Również to złączenie używa dwóch tabel,
   wartości forum_id z tabeli messages              users i messages. Złączenie obu tabel odbywa
   odpowiadającą jej wartością name z tabeli        się za pomocą kolumny user_id i dlatego
   forums dla każdego rekordu tabeli messages.      została ona umieszczona wewnątrz klauzuli
   W wyniku otrzymasz zatem temat każdej            USING. Wyrażenie warunkowe WHERE pozwala
   wiadomości wraz z nazwą forum, do którego        zidentyfikować interesującego nas użytkownika,
   należy ta wiadomość.                             a funkcja DATE_FORMAT sformatować wartość
                                                    pola date_entered.
   Zwróć uwagę, że w połączeniach nadal
   możesz używać klauzul ORDER BY.




                                                                                                      Złączenia
Rysunek 6.18. Podstawowe złączenie wewnętrzne    Rysunek 6.19. Nieco bardziej skomplikowana wersja
zwraca w tym przykładzie tylko dwie kolumny      złączenia wewnętrznego tabele users i messages




                                                                                                193
Rozdział 6.


             3. Pobierz identyfikator wiadomości, temat oraz            4. Dla każdego użytkownika pobierz nazwę
                  nazwę forum dla każdej wiadomości, której               użytkownika, temat wiadomości i nazwę
                  autorem jest użytkownik janek (patrz                    forum (patrz rysunek 6.21).
                  rysunek 6.20).                                             SELECT u.username, m.subject,
                    SELECT m.message_id, m.subject,                          f.name FROM users AS u LEFT JOIN
                      f.name FROM users AS u                                 messages AS m USING (user_id)
                      INNER JOIN                                             LEFT JOIN forums AS f
                      messages AS m USING (user_id)                          USING (forum_id);
                      INNER JOIN forums AS f
                      USING (forum_id)                                    Gdybyś zastosował podobne złączenie
                      WHERE u.username = 'janek';                         wewnętrzne, to użytkownicy, którzy nie
                                                                          są jeszcze autorami żadnej wiadomości,
                  Powyższe złączenie jest podobne                         nie zostaliby uwzględnieni (patrz rysunek
                  do zastosowanego w punkcie 2., ale idzie o krok         6.22). Zatem jeśli interesują Cię wszyscy
                  dalej, dołączając trzecią tabelę. Zwróć szczególną      użytkownicy, powinieneś użyć złączenia
                  uwagę na sposób konstrukcji złączenia                   zewnętrznego. Zwróć uwagę, że tabela,
                  wewnętrznego trzech tabel oraz zastosowanie             która ma być uwzględniona w całości
                  aliasów w celu łatwiejszego odwoływania się             (users w tym przypadku), musi być podana
                  do tabel i ich kolumn.                                  jako pierwsza tabela złączenia typu left.
Złączenia




            Rysunek 6.20. Złączenie wewnętrzne wszystkich trzech       Rysunek 6.21. To złączenie zewnętrzne zwraca
            tabel bazy                                                 dla każdego użytkownika temat każdej wiadomości
                                                                       i nazwę każdego forum. Jeśli użytkownik nie umieścił
                                                                       jeszcze żadnej wiadomości na forum (tak jak tomekj
                                                                       widoczny na dole rysunku), to temat wiadomości
                                                                       i nazwa forum będą mieć dla niego wartości NULL




            194
Zaawansowany SQL i MySQL


Wskazówki                                          Złączenia, które nie zawierają klauzuli WHERE
                                                   (np. SELECT * FROM urls, url_associations),
  Możesz nawet złączyć tabelę z nią samą.
                                                   nazywamy złączeniami pełnymi. Zwracają one
  Złączenia można tworzyć z wykorzystaniem         rekordy z obu tabel. W przypadku dużych tabel
  wyrażeń warunkowych odwołujących się             ilość zwracanych danych może stanowić pewien
  do dowolnych kolumn. Nie muszą one               problem.
  pełnić roli kluczy, choć sytuacja taka jest
                                                   Nigdy nie zostanie zwrócona wartość NULL
  najczęstsza.
                                                   występująca w kolumnie, do której odwołujemy
  Stosując składnię bazadanych.tabela.             się w złączeniu. To dlatego, że nie jest ona równa
  kolumna, możesz wykonywać złączenia              żadnej innej wartości, w tym także innym
  tabeli należących do różnych baz danych,         wartościom NULL.
  o ile tylko wszystkie znajdują się na tym
  samym serwerze. Ta metoda nie zadziała,
  jeżeli bazy komunikują się ze sobą
  za pośrednictwem sieci.




                                                                                                        Złączenia
                         Rysunek 6.22. To złączenie wewnętrzne nie zwróci
                         użytkownika, który nie umieścił jeszcze żadnej
                         wiadomości na forum (tak jak tomekj widoczny
                         na dole rysunku 6.21)




                                                                                                  195
Rozdział 6.


                               Grupowanie wyników zapytania                             Aby zgrupować dane:

                               W poprzednim rozdziale przedstawiłem dwie                 1. Policz zarejestrowanych użytkowników
                               różne klauzule — ORDER BY i LIMIT — mające wpływ            (patrz rysunek 6.23).
                               na wynik zapytania. Pierwsza z nich umożliwia                  SELECT COUNT(user_id) FROM users;
                               określenie uporządkowania zwracanych rekordów,
                                                                                           COUNT() jest prawdopodobnie
                               a druga pozwala określić, które z rekordów będących
                                                                                           najpopularniejszą z funkcji agregujących.
                               wynikiem zapytania zostaną w rzeczywistości
                                                                                           Z jej pomocą możesz szybko zliczyć
                               zwrócone. Kolejna klauzula, GROUP BY, grupuje
                                                                                           rekordy tak jak w przypadku tabeli users.
                               zwracane dane w podobne do siebie bloki informacji.
                                                                                           Zwróć uwagę, że nie wszystkie zapytania
                               Na przykład, aby pogrupować wszystkie wiadomości
                                                                                           stosujące funkcje agregujące używają
                               według forum, wpisz:
                                                                                           klauzuli GROUP BY.
                                 SELECT * FROM messages
                                   GROUP BY forum_id;                                    2. Policz, ile razy każdy użytkownik umieścił
                                                                                           na forum swoją wiadomość (patrz
                               Zwracane dane nie będą miały postaci pojedynczych
                                                                                           rysunek 6.24).
                               rekordów, tylko grup informacji. Zamiast dużej
                               liczby wiadomości pochodzących z danego forum                  SELECT username,
                                                                                              COUNT(message_id) AS Number
                               zobaczysz je wszystkie w postaci jednego rekordu.              FROM users LEFT JOIN messages AS m
                               Ten przykład nie jest być może szczególnie                     USING (user_id) GROUP BY (m.user_id);
                               przydatny, ale wystarczający do przedstawienia
                               samej koncepcji.
Grupowanie wyników zapytania




                               Z klauzulą GROUP BY często używa się jednej z funkcji Tabela 6.7. Funkcje grupujące MySQL-a
                               agregujących przedstawionych w tabeli 6.7 (funkcji
                               tych można używać również niezależnie od klauzuli Funkcja              Przeznaczenie

                               GROUP BY).                                             AVG()           Zwraca średnią wartość z podanej
                                                                                                          kolumny.
                               Na wyrażenie GROUP BY możesz oczywiście nakładać          MIN()            Zwraca najmniejszą wartość
                               warunki WHERE, ORDER BY i LIMIT, tworząc zapytania                         z podanej kolumny.
                               w rodzaju:                                                MAX()            Zwraca największą wartość z podanej
                                                                                                          kolumny.
                                 SELECT kolumny FROM tabela WHERE warunek
                                                                                         SUM()            Zwraca sumę wszystkich wartości
                                   GROUP BY kolumna ORDER BY kolumna
                                                                                                          z danej kolumny.
                                   LIMIT x, y;
                                                                                         COUNT()          Zwraca liczbę rzędów.
                                                                                         GROUP_CONCAT() Zwraca konkatenację wartości
                                                                                                        kolumny.




                                                                                        Rysunek 6.23. To zapytanie grupujące zwraca
                                                                                        liczbę wartości user_id w tabeli users


                               196
Zaawansowany SQL i MySQL


   Jest to rozszerzona wersja zapytania               W zapytaniach z klauzulą GROUP BY nadal możesz
   występującego w kroku 1., ale zamiast              sortować wyniki zapytań. Proces ten możesz
   zliczać samych użytkowników, podaje                uprościć, stosując alias Number dla wartości
   liczbę wiadomości związanych z każdym              COUNT(message_id).
   użytkownikiem. Zastosowanie złączenia
   umożliwia dostęp do informacji w dwóch           Wskazówki
   tabelach. Aby uwzględnić użytkowników,             Jak już miałeś okazję się przekonać, NULL
   którzy nie byli jeszcze aktywni na forum,
                                                      jest bardzo specyficzną wartością. Interesujące
   zastosowałem złączenie wewnętrzne.
                                                      jest to, że wyrażenie GROUP BY umieszcza
 3. Znajdź dwóch najaktywniejszych
                                                      wszystkie wartości NULL w tej samej grupie,
   użytkowników forum (rysunek 6.25).                 ponieważ wszystkie one wykazują taki sam
                                                      „brak wartości”.
     SELECT username,
       COUNT(message_id) AS Number                    Funkcja COUNT() zlicza jedynie wystąpienia
       FROM users                                     wartości różnych od NULL. Dlatego pamiętaj,
       LEFT JOIN messages AS m
       USING (user_id)                                aby użyć jej dla każdej kolumny (*) lub
       GROUP BY (m.user_id)                           dla kolumn, które nie zawierają wartości NULL
       ORDER BY Number DESC LIMIT 2;                  (na przykład klucza głównego). Jeśli zapytanie
                                                      użyte w punkcie 2. (rysunek 6.24) stosowałoby
                                                      funkcję COUNT() dla wszystkich kolumn (*)
                                                      zamiast tylko dla message_id, to pokazałoby




                                                                                                         Grupowanie wyników zapytania
                                                      błędną wartość równą 1 dla wszystkich
                                                      użytkowników, którzy nie napisali jeszcze żadnej
                                                      wiadomości. Stałoby się tak, ponieważ zapytanie
                                                      zwróciłoby dokładnie jeden rekord dla każdego
                                                      z tych użytkowników.
                                                      Opanowanie klauzuli GROUP BY i funkcji
                                                      omówionych w tym podrozdziale zajmie Ci
                                                      trochę czasu. Za każdym razem, gdy użyjesz
Rysunek 6.24. To zapytanie GROUP BY podaje liczbę
wiadomości umieszczonych na forum przez każdego       nieprawidłowej składni, zostanie zgłoszony
użytkownika                                           błąd. Poeksperymentuj trochę z monitorem
                                                      mysqla, aby zapamiętać, jak dokładnie muszą
                                                      być sformułowane wszystkie zapytania, których
                                                      będziesz chciał używać w swoich aplikacjach.
                                                      Z klauzulą GROUP BY związana jest klauzula
                                                      HAVING, która zachowuje się jak klauzula WHERE
                                                      zastosowana do grupy rekordów.




Rysunek 6.25. Klauzula ORDER BY pozwala
posortować autorów na podstawie liczby wiadomości
umieszczonych na forum. Klauzula LIMIT powoduje,
że podane zostaną tylko dwa wyniki


                                                                                                  197
Rozdział 6.


          Indeksy                                               Wyposażony w te wiadomości zmodyfikuję
                                                                bazę forum, dodając do niej indeksy.
          Mechanizm indeksów to specjalny system                W tabeli 6.8 podałem indeksy utworzone
          wykorzystywany w bazach danych do poprawy             dla poszczególnych kolumn za pomocą
          ich wydajności. Zakładając na swych tabelach          polecenia ALTER omówionego w ramce.
          indeksy, sprawiasz, że MySQL przywiązuje wagę
          do określonych kolumn. Aby indeksy mogły być
          wykorzystywane w sposób maksymalnie efektywny,
          MySQL przechowuje je w osobnych plikach.
          Na każdej tabeli można założyć co najmniej 16
          indeksów, a każdy indeks może obejmować do 15
          kolumn. Choć rozciąganie indeksu na kilka kolumn
          może wydawać się zastanawiające, przydaje się to
          podczas częstego przeszukiwania tego samego
          zestawu kolumn (np. imion i nazwisk, miast
          i województw).
          Nie powinieneś jednak przesadzać z indeksowaniem.
          Choć przyspiesza ono odczytywanie informacji
          z bazy, to jednocześnie spowalnia ich modyfikowanie
          (ponieważ informacje o zmianach muszą trafić
          do indeksów). Najlepszym wyjściem jest zakładanie
          indeksów na kolumnach, które:
                Często wymieniane są w zapytaniach
                po klauzulach WHERE.
                                                                Tabela 6.8. Indeksy używane przez bazę danych
Indeksy




                Często wymieniane są w zapytaniach              forum. Nie wszystkie kolumny są indeksowane,
                po klauzulach ORDER BY.                         a dwa indeksy zostały utworzone dla par kolumn:
                                                                user.pass i user.username oraz messages.body
                Często wykorzystywane są jako główny punkt
                                                                i messages.subject
                złączenia.
                                                                Indeksy bazy danych forum
                Mają wiele różnych wartości (nie powinno się
                                                                Nazwa kolumny    Tabela     Typ indeksu
                indeksować kolumn zawierających wiele
                                                                forum_id         forums     PRIMARY
                powtarzających się wartości).
                                                                name             forums     UNIQUE
          W MySQL-u występują cztery rodzaje indeksów:          message_id       messages   PRIMARY
          INDEX (standardowy), UNIQUE (który wymaga,            forum_id         messages   INDEX
          aby w każdym rzędzie występowały inne wartości),      parent_id        messages   INDEX
          FULLTEXT (do wyszukiwań FULLTEXT) oraz PRIMARY KEY    user_id          messages   INDEX
          (klucz główny, będący szczególnym przypadkiem         body/subject     messages   FULLTEXT
          indeksu UNIQUE). Pamiętaj, że dana kolumna może
                                                                date_entered     messages   INDEX
          być tylko raz zaindeksowana i wobec tego wybierz
                                                                user_id          users      PRIMARY
          dla niej najodpowiedniejszy rodzaj indeksu.
                                                                username         users      UNIQUE
                                                                pass/username    users      INDEX
                                                                email            users      UNIQUE


          198
Zaawansowany SQL i MySQL


                                                    Aby dodać indeks do istniejącej tabeli:
                                                     1. Załóż indeks na kolumnie name w tabeli forums
                                                        (patrz rysunek 6.26).
                                                          ALTER TABLE forums ADD UNIQUE (name);
Rysunek 6.26. Dla kolumny name dodano nowy              Tabela forums ma już założony indeks typu klucz
indeks, który poprawi efektywność zapytań               główny na kolumnie forum_id. Ponieważ name
i zapobiegnie wprowadzaniu powtarzających się
                                                        również jest polem, do którego będą częste
wartości
                                                        odwołania i którego wartość musi być unikatowa
                                                        w każdym rekordzie, zakładam na nim indeks
                                                        UNIQUE.




                                        Modyfikowanie tabel
  Polecenie ALTER służy przede wszystkim do modyfikowania struktury tabeli w bazie danych.
  Najczęściej oznacza to dodawanie, usuwanie bądź modyfikację kolumn, ale również dodawanie
  indeksów. Polecenia ALTER można również użyć do zmiany nazwy tabeli. Teoretycznie przy dobrym




                                                                                                                        Indeksy
  projekcie bazy jej struktura nie powinna stwarzać żadnych problemów. Jednak w praktyce często
  zdarza się wprowadzać w niej pewne zmiany. Składnia polecenia ALTER jest następująca:
    ALTER TABLE nazwa_tabeli KLAUZULA;
  Ponieważ klauzul, które można zastosować, jest bardzo wiele, w tabeli 6.9 wymieniłem tylko najczęściej
  stosowane. Pełną listę znajdziesz w podręczniku MySQL-a.

  Tabela 6.9. Popularne warianty polecenia ALTER (gdzie t reprezentuje nazwę tabeli, c nazwę kolumny,
  a i nazwę indeksu. Pełną specyfikację polecenia znajdziesz w dokumentacji MySQL-a
   Klauzule, które można stosować w poleceniach ALTER TABLE
   Klauzula         Sposób użycia                             Znaczenie
   ADD COLUMN       ALTER TABLE t ADD COLUMN c TYP            Dodaje nową kolumnę na końcu tabeli.
   CHANGE COLUMN    ALTER TABLE t CHANGE COLUMN c c TYP       Pozwala zmienić typ danych i właściwości kolumny.
   DROP COLUMN      ALTER TABLE t DROP COLUMN c               Usuwa kolumnę z tabeli razem z wszystkimi jej
                                                              danymi.
   ADD INDEX        ALTER TABLE t ADD INDEX i (c)             Zakłada nowy indeks na kolumnie c.
   DROP INDEX       ALTER TABLE t DROP INDEX i                Usuwa istniejący indeks.
   RENAME AS        ALTER TABLE t RENAME AS nowa_t            Zmienia nazwę tabeli.




                                                                                                                  199
Rozdział 6.


           2. Załóż indeksy dla tabeli messages                      Jesli podczas wykonywania tego zapytania
             (patrz rysunek 6.27).                                   pojawi się komunikat o błędzie
                ALTER TABLE messages                                 stwierdzający, że typ tabeli nie obsługuje
                ADD INDEX(forum_id),                                 indeksów FULLTEXT (patrz rysunek 6.28),
                ADD INDEX(parent_id),                                na razie opuść ten wiersz zapytania
                ADD INDEX(user_id),                                  i sprawdź w następnym podrozdziale,
                ADD FULLTEXT(body, subject),
                ADD INDEX(date_entered);                             w jaki sposób zmienić typ tabeli.

             Ta tabela będzie mieć najwięcej indeksów,
             ponieważ jest najważniejszą tabelą w bazie
             i zawiera trzy klucze obce (forum_id, parent_id
             i user_id), dla których należy założyć osobne
             indeksy. Dodatkowo pola body i subject
             otrzymują indeks FULLTEXT używany podczas
             wyszukiwań typu FULLTEXT w dalszej części
             tego rozdziału. Również kolumna date_entered
                                                                 Rysunek 6.27. Do tabeli messages dodano kilka
             otrzymuje indeks, ponieważ będzie używana
                                                                 indeksów naraz. MySQL raportuje wykonanie
             przez klauzule ORDER BY (do sortowania              operacji oraz podaje liczbę rekordów, których
             wiadomości po dacie).                               dotyczyła (powinna to być liczba wszystkich
                                                                 rekordów tabeli)
Indeksy




                         Rysunek 6.28. Indeksów FULLTEXT nie można stosować dla wszystkich typów
                         tabel. Jeśli napotkasz ten komunikat o błędzie, to rozwiązanie znajdziesz
                         w tym rozdziale w części „Stosowanie różnych typów tabel”




          200
Zaawansowany SQL i MySQL


 3. Dodaj indeksy do tabeli users                    Indeks założony na kolumnach pass i username
   (patrz rysunek 6.29).                             ma za zadanie poprawić efektywność zapytań
     ALTER TABLE users                               wykonywanych podczas uwierzytelniania
     ADD UNIQUE (username),                          użytkownika, gdy kombinacja tych dwóch
     ADD INDEX (pass, username),                     kolumn będzie używana w wyrażeniu
     ADD UNIQUE (email);                             warunkowym WHERE.
   Tabela users będzie mieć dwa indeksy           4. Obejrzyj bieżącą strukturę wszystkich tabel
   UNIQUE oraz jeden indeks założony na dwóch        (patrz rysunek 6.30).
   kolumnach. Indeksy UNIQUE zastosowałem
                                                       DESCRIBE forums;
   w tym przypadku, ponieważ chcę zapobiec             DESCRIBE messages;
   możliwości zarejestrowania dwóch                    DESCRIBE users;
   użytkowników o tej samej nazwie
   lub wielokrotnego zarejestrowania                 Polecenie DESCRIBE języka SQL zwraca
   użytkownika o tym samym adresie e-mail.           informacje o nazwach kolumn występujących
                                                     w tabeli i w ich typach, a także o kolejności,
                                                     w jakiej one występują i o pozakładanych
                                                     indeksach. Podaje ono także, czy dane pole
                                                     może przyjmować wartość NULL, czy określono
                                                     dla niego jakąś wartość domyślną itd.



Rysunek 6.29. Indeksy zostały również
dodane do trzeciej tabeli




                                                                                                      Indeksy




Rysunek 6.30. Aby zobaczyć szczegółowe informacje na temat struktury tabeli,
użyj polecenia DESCRIBE. Kolumna Key informuje o indeksach


                                                                                                201
Rozdział 6.


          Wskazówki
             Próba założenia indeksu UNIQUE na kolumnie
             zawierającej duplikaty spowoduje błąd, a indeks
             nie zostanie utworzony.
             Tworząc indeks, możesz nadać mu nazwę.
                ALTER TABLE tabela
                  ADD INDEX nazwa_indeksu (kolumna);

             Jeżeli tego nie zrobisz, otrzyma on nazwę
             kolumny, na której go zakładasz.
             Słowo COLUMN w większości poleceń ALTER
             jest opcjonalne.
             Załóżmy, że stworzyłeś indeks dla kilku kolumn:
                ALTER TABLE tabela
                  ADD INDEX (kol1, kol2, kol3)

             Powstały indeks umożliwia efektywne
             przeszukiwanie kolumny kol1, kombinacji
             kolumn kol1 i kol2 oraz kombinacji wszystkich
             trzech podanych kolumn. Nie zwiększa
             efektywności przeszukiwania kolumny kol2
             i kol3 lub ich kombinacji.
Indeksy




          202
Zaawansowany SQL i MySQL


Stosowanie                                        Aby określić, którego silnika chcemy używać,
                                                  na końcu polecenia CREATE dodajemy specjalną
różnych typów tabeli                              klauzulę:
MySQL obsługuje kilka różnych typów tabeli          CREATE TABLE tabela (
(typ tabeli nazywany bywa również silnikiem         kolumna1 TYPKOLUMNY,
                                                    kolumna2 TYPKOLUMNY...
przechowywania). Każdy z tych typów ma inne         ) ENGINE = INNODB
właściwości, odrębne ograniczenia (dotyczące
ilości przechowywanych danych)                    Jeśli tworząc tabele, nie podamy ich typu, to MySQL
i charakteryzuje się inną efektywnością           użyje typu domyślnego.
działania w określonych sytuacjach. Jednak        Typ istniejącej tabeli możemy zmienić za pomocą
interakcje użytkownika (w sensie wykonywania      polecenia ALTER:
zapytań) z różnymi typami tabel są spójne.
                                                    ALTER TABLE tabela ENGINE = MYISAM
Najważniejszym typem tabeli jest MyISAM. Jest
on domyślnym typem tabeli na wszystkich           Ponieważ następny przykład w tym rozdziale będzie
platformach oprócz Windows. Tabele tego           wymagać tabeli typu MyISAM, to pokażę najpierw
typu są najodpowiedniejsze dla większości         kroki konieczne do skonfigurowania odpowiedniego
aplikacji i umożliwiają szybkie wykonywanie       typu tabeli na przykładzie tabeli messages. W kilku
poleceń SELECT oraz INSERT. Ich podstawową        pierwszych krokach dowiesz się, jak sprawdzić
wadą jest to, że nie obsługują transakcji.        wykorzystywany typ silnika, (ponieważ zmiana
                                                  typu tabeli może nie być konieczna).




                                                                                                        Stosowanie różnych typów tabeli
Kolejnym typem tabeli pod względem
popularności zastosowań jest InnoDB, który jest
domyślnym typem tabeli MySQL-a w systemie
Windows. Tabele InnoDB obsługują transakcje
i umożliwiają szybkie wykonywanie poleceń
UPDATE. Jednak silnik InnoDB jest w ogólnym
przypadku wolniejszy niż MyISAM i wymaga
większej przestrzeni dyskowej serwera. Tabele
typu InnoDB nie obsługują również indeksów
typu FULLTEXT (i dlatego mogłeś napotkać błąd
przedstawiony na rysunku 6.28, jeśli używasz
Windows).




                                                                                                 203
Rozdział 6.


                                  Aby zmienić typ tabeli:                                 2. Jeśli to konieczne, zmień typ tabeli
                                                                                             messages na MyISAM (rysunek 6.32).
                                   1. Obejrzyj aktualną informację o tabeli
                                     (patrz rysunek 6.31).                                     ALTER TABLE messages ENGINE=MYISAM;

                                        SHOW TABLE STATUS;                                   Jeśli w punkcie 1. okazało się, że typ
                                                                                             tabeli jest inny niż MyISAM, to zmień go
                                     Polecenie SHOW TABLE STATUS zwraca wiele
                                                                                             za pomocą powyższego polecenia
                                     przydatnych informacji o tabelach bazy danych.
                                                                                             (nie musisz zwracać uwagi na małe i duże
                                     Informacje te odczytuje się niewygodnie,
                                                                                             litery w typie tabeli). Jeśli wykonałeś
                                     ponieważ mają one postać szerokiej tabeli
                                                                                             domyślną instalację i konfigurację
                                     zajmującej wiele wierszy. W każdym wierszu
                                                                                             MySQL-a, to zmiana typu tabeli nie
                                     znajduje się najpierw nazwa tabeli, a następnie
                                                                                             będzie potrzebna w systemie Mac OS X,
                                     jej typ. Zwykle jest nim MyISAM lub InnoDB.
                                                                                             ale musisz jej dokonać w systemie
                                                                                             Windows.
Stosowanie różnych typów tabeli




                                                     Rysunek 6.31. Zanim zmienisz typ tabeli, sprawdź go za pomocą
                                                     polecenia SHOW TABLE STATUS




                                                              Rysunek 6.32. Zmieniłem typ tabeli (lub silnik
                                                              przechowywania) za pomocą polecenia ALTER




                                  204
Zaawansowany SQL i MySQL


                                                3. Możesz sprawdzić zmianę typu tabeli, wykonując
                                                   ponownie polecenie SHOW TABLE STATUS.

                                                Wskazówki
                                                  Aby ułatwić odczytanie wyników dowolnego
                                                  zapytania, możesz dodać w kliencie mysqla
                                                  parametr G na końcu zapytania (rysunek 6.33):
                                                    SHOW TABLE STATUS G

                                                  Znacznik ten informuje, że tabela wyników
Rysunek 6.33. Aby uzyskać bardziej czytelną       powinna zostać wyświetlona pionowo zamiast
postać wyników zapytania, użyłem znacznika G     poziomo. Zwróć uwagę, że nie musisz w tym
                                                  przypadku użyć średnika kończącego polecenie
                                                  SQL, ponieważ funkcję tę spełnia znacznik G.
                                                  W tej samej bazie danych mogą występować
                                                  różne typy tabel. W zależności od domyślnego
                                                  typu tabel w Twojej instalacji MySQL-a,
                                                  stwierdzenie to może już być prawdziwe dla bazy
                                                  danych forum. To samo możesz zaobserwować
                                                  w przypadku bazy danych ecommerce, w której




                                                                                                    Stosowanie różnych typów tabeli
                                                  tabele klientów i produktów są typu MyISAM,
                                                  ale tabela zamówień jest typu InnoDB
                                                  (aby umożliwić stosowanie transakcji).




                                                                                             205
Rozdział 6.


                        Wyszukiwanie FULLTEXT                                  Realizacja podstawowego wyszukiwania
                                                                               FULLTEXT
                        W rozdziale 5. przedstawiłem słowo kluczowe LIKE
                        umożliwiające proste porównania łańcuchów,       Po założeniu indeksu FULLTEXT możesz
                        na przykład:                                     wydawać zapytania przy użyciu funkcji MATCH
                                                                         i AGAINST w wyrażeniach warunkowych WHERE:
                          SELECT * FROM users
                          WHERE last_name LIKE 'Kowalsk%';                       SELECT * FROM tabela
                                                                                   WHERE MATCH (kolumna)
                        W ten sposób nie wykonamy jednak wyszukiwań                AGAINST('poszukiwane_słowa')
                        z zastosowaniem wielu słów. Aby stało się to
                        możliwe, wprowadzono wyszukiwania FULLTEXT.            MySQL zwróci pasujące rekordy począwszy
                                                                               od spełniających warunek wyszukiwania
                        Wyszukiwania FULLTEXT wymagają obecności               w największym stopniu. Podczas wyszukiwania
                        indeksu FULLTEXT, który można założyć jedynie          stosowane są następujące reguły:
                        na tabelach typu MyISAM. W następnych przykładach         Łańcuchy rozbijane są na poszczególne
                        będę używać tabeli messages bazy forum. Jeśli             słowa.
                        utworzona przez Ciebie tabela messages nie jest typu
                                                                                  Słowa krótsze niż 4-znakowe są ignorowane.
                        MyISAM i (lub) nie ma indeksu FULLTEXT założonego
                        na kolumnach body i subject, wykonaj kroki podane         Słowa często używane są ignorowane.
                        na kilku poprzednich stronach, aby to zmienić.
                                                                                  Jeśli ponad połowa rekordów spełnia
                        Wskazówki                                                 warunek wyszukiwania, to nie jest zwracany
                                                                                  żaden rekord.
Wyszukiwanie FULLTEXT




                           Wstawianie rekordów do tabel, na których
                           założono indeks FULLTEXT, może być znacznie         Zwłaszcza ostatnia reguła jest zaskakująca
                           wolniejsze ze względu na skomplikowaną              dla wielu użytkowników, którzy rozpoczynają
                           naturę tego indeksu.                                dopiero przygodę z wyszukiwaniami FULLTEXT
                                                                               i dziwią się, dlaczego nie zwracają one żadnych
                           Indeks FULLTEXT możemy zakładać na wielu            wyników. Jeśli wypełnisz tabelę zbyt małą
                           kolumnach, jeśli wszystkie mają być                 liczbą rekordów, to MySQL nie zwróci
                           przeszukiwane.                                      właściwych wyników.
                           Wyszukiwania FULLTEXT mogą służyć
                           do implementacji prostych usług wyszukiwania.
                           Ponieważ jednak indeks FULLTEXT stosuje
                           się do jednej tabeli, to usługi wyszukiwania
                           informacji w wielu tabelach wymagają
                           zastosowania bardziej zaawansowanych
                           rozwiązań.




                        206
Zaawansowany SQL i MySQL


Aby wykonać wyszukiwanie FULLTEXT:                 Ten prosty przykład zwróci wynik pod
                                                   warunkiem, że co najmniej jeden rekord i mniej
 1. Wypełnij tabelę messages dużą ilością
                                                   niż połowa rekordów tabeli messages zawiera
    danych — zwłaszcza w polu body.
                                                   słowo tabela w polu body lub subject. Zwróć
  Możesz użyć w tym celu poleceń INSERT            uwagę, że kolumny, do których odwołuje się
  ściągniętych z serwera ftp.                      MATCH, muszą być tymi samymi kolumnami,
                                                   jakie podałeś, tworząc indeks FULLTEXT. W tym
2. Wykonaj proste wyszukiwanie FULLTEXT
                                                   przykładzie mogłeś zatem użyć albo body,
  dla słowa skrypt (patrz rysunek 6.34).
                                                   subject, albo subject, body, ale nie samych body
    SELECT subject, body FROM messages             lub subject (patrz rysunek 6.35).
     WHERE MATCH (body, subject)
     AGAINST ('skrypt');




   Rysunek 6.34. Podstawowe wyszukiwanie FULLTEXT




                                                                                                      Wyszukiwanie FULLTEXT
              Rysunek 6.35. Zapytanie FULLTEXT możesz wykonać jedynie na tej samej
              kolumnie lub kombinacji kolumn, dla której utworzyłeś indeks FULLTEXT.
              W tym przypadku zapytanie zakończy się błędem, mimo że kombinacja
              kolumn body i subject ma indeks FULLTEXT




                                                                                               207
Rozdział 6.


                         3. Wykonaj to samo wyszukiwanie FULLTEXT,              Wskazówki
                           pokazując dodatkowo stopień spełnienia
                                                                                   Pamiętaj, że jeśli wyszukiwanie FULLTEXT
                           warunku przez poszczególne rekordy (patrz
                           rysunek 6.36).                                          nie zwróci żadnych rekordów, to albo żaden
                                                                                   rekord nie spełnia warunku wyszukiwania,
                              SELECT subject, body,                                albo spełnia go ponad połowa rekordów.
                               MATCH (body, subject)
                               AGAINST('skrypt') AS R                              Dla uproszczenia wszystkie zapytania
                               FROM messages
                               WHERE MATCH (body, subject)
                                                                                   przedstawione w tym podrozdziale
                               AGAINST('skrypt');                                  zapisałem jako najprostsze polecenia SELECT.
                                                                                   Wyszukiwania FULLTEXT można też używać
                           Jeśli użyjesz tego samego wyrażenia                     w bardziej skomplikowanych zapytaniach
                           MATCH...AGAINST jako wybieranej wartości,               czy złączeniach.
                           to pokazany zostanie również stopień spełnienia
                           warunku przez rekordy.                                  MySQL zawiera w kodzie źródłowym
                                                                                   listę kilkuset słów pospolitych, które są
                         4. Wykonaj wyszukiwanie FULLTEXT stosując kilka           ignorowane w wyszukiwaniach FULLTEXT.
                           słów (rysunek 6.37).
                                                                                   Minimalną długość wyszukiwanego słowa
                              SELECT subject, body
                               FROM messages                                       (wynoszącą domyślnie 4 znaki) można
                               WHERE MATCH (body, subject)                         konfigurować.
                               AGAINST('projekt formularz');
                                                                                   Domyślnie wyszukiwania FULLTEXT
                           W tym przypadku rekord spełni warunek                   nie rozróżniają małych i wielkich liter.
                           wyszukiwania, jeśli pole subject lub body
Wyszukiwanie FULLTEXT




                           będzie zawierać jedno z podanych słów. Rekord
                           zawierający oba słowa uzyska wyższy stopień
                           spełnienia warunku.




                        Rysunek 6.36. Możesz również zobaczyć stopień spełniania warunku wyszukiwania przez poszczególne rekordy




                        Rysunek 6.37. Wyszukiwanie FULLTEXT można także stosować dla wielu słów


                        208
Zaawansowany SQL i MySQL


Wyszukiwania FULLTEXT                       Znak maski (*) umożliwia wyszukiwanie różnych
w trybie Boolean                            wariantów słowa. Na przykład zastosowanie go
                                            w słowie bezpiecz* spowoduje wyszukanie rekordów
Bardziej zaawansowane wyszukiwania FULLTEXT zawierających słowa bezpieczny, bezpieczeństwo
można wykonywać, korzystając z trybu        i tym podobnych. Dwa kolejne operatory
Boolean. W trybie tym używamy wyrażenia     umożliwiają określenie, że dane słowo jest mniej (<)
IN BOOLEAN MODE wewnątrz klauzuli AGAINST: lub bardziej (>) ważne. Znaki cudzysłowu pozwalają
  SELECT * FROM tabela WHERE                wyszukiwać całe frazy, a nawiasy — tworzyć
    MATCH(kolumny)                          podwyrażenia.
     AGAINST('poszukiwane_słowa'
       IN BOOLEAN MODE)                                  Poniższe zapytanie wyszuka rekordy zawierające
W trybie Boolean możemy stosować szereg                  frazę serwer WWW oraz słowo html. Obecność
operatorów (tabela 6.10) określających sposób            słowa JavaScript obniży wartość rekordu jako
traktowania każdego wyszukiwanego słowa:                 wyniku wyszukiwania.
                                                           SELECT * FROM tabela WHERE
    SELECT * FROM tabela WHERE
                                                           MATCH (kolumny) AGAINST('>"serwer WWW" +html
     MATCH(kolumny)
                                                             ~JavaScript' IN BOOLEAN MODE)
     AGAINST('+baza -mysql' IN BOOLEAN MODE)

W tym przykładzie rekord zostanie wybrany,               W trybie Boolean pojawiają się następujące różnice
                                                         w sposobie działania wyszukiwania FULLTEXT:
jeśli zawiera słowo baza i nie zawiera słowa
mysql. Jako słabszą formę operatora                         Jeśli słowo nie jest poprzedzone żadnym
reprezentowanego przez znak minus ( -)                      operatorem, to jest opcjonalne, ale podnosi
możemy stosować tyldę (~). Oznacza ona,                     wartość rekordu, który je zawiera.




                                                                                                                Wyszukiwanie FULLTEXT
że rekord może zawierać dane słowo,
                                                            Wyniki są zwracane nawet wtedy, gdy ponad
ale wtedy w mniejszym stopniu spełnia
                                                            połowa rekordów spełnia warunek
warunek wyszukiwania.
                                                            wyszukiwania.
                                                            Wyniki nie są automatycznie sortowane
                                                            na podstawie stopnia, w jakim spełniają warunek
Tabela 6.10. Operatory umożliwiające
                                                            wyszukiwania.
precyzyjniejsze wyszukiwanie FULLTEXT
Operatory dostępne w trybie Boolean                      Z uwagi na tę ostatnią właściwość można
                                                         samodzielnie posortować rekordy według
Operator     Znaczenie
                                                         stopnia w jakim spełniają warunek wyszukiwania,
+            Rekord musi zawierać słowo poprzedzone
                                                         co zaprezentuję w kilku następnych krokach.
             tym operatorem.
                                                         W przypadku wyszukiwań w trybie Boolean nadal
-            Rekord nie może zawierać słowa
             poprzedzonego tym operatorem.               obowiązuje zasada, że słowa krótsze niż 4-znakowe
~            Słowo poprzedzone tym operatorem obniża     są ignorowane. Nie zmienia tego użycie operatora
             wartość rekordu jako wyniku wyszukiwania.   +, na przykład słowo +php zostanie zignorowane.
*            Maska wyszukiwania.
<            Zmniejsza znaczenie słowa.
>            Zwiększa znaczenie słowa.
""           Rekord musi zawierać frazę umieszczoną
             w znakach cudzysłowu.
()           Tworzy podwyrażenie.



                                                                                                          209
Rozdział 6.


                        Aby wykonać wyszukiwanie FULLTEXT                       2. Wykonaj zapytanie wyszukujące
                        w trybie Boolean:                                          wiadomości dotyczące tabel
                                                                                   ze szczególnym uwzględnieniem
                         1. Wykonaj proste wyszukiwanie FULLTEXT różnych
                                                                                   zawierających termin normalizacja
                              przypadków słowa baza (bazy, bazie itp.)
                                                                                   (patrz rysunek 6.39).
                              (patrz rysunek 6.38).
                                                                                     SELECT subject, body FROM messages
                                SELECT subject, body FROM                             WHERE MATCH(body, subject)
                                 messages WHERE MATCH(body, subject)                  AGAINST ('>formularz* +skrypt*'
                                 AGAINST('baz*' IN BOOLEAN MODE) G                   IN BOOLEAN MODE)G
                              Słowo baza może pojawić się w wiadomościach          Zapytanie to najpierw wyszukuje
                              forum w wielu różnych przypadkach takich             wszystkie rekordy zawierające słowo
                              jak bazy lub bazie. Powyższe zapytanie wyszuka       skrypt* (skryptu, skrypty, …) i formularz*
                              rekordy zawierające te przypadki dzięki              (formularz, formularza, formularzy, …).
                              zastosowaniu znaku maski (*).                        Obecność terminu skrypt* jest wymagana
                              Dodatkowo zastosowałem znacznik G,                  (na co wskazuje operator +), natomiast
                              aby łatwiej przeanalizować wyniki.                   wyróżnione zostają rekordy zawierające
                                                                                   termin formularz* (na co wskazuje
                                                                                   operator >).
Wyszukiwanie FULLTEXT




                        Rysunek 6.38. Proste wyszukiwanie FULLTEXT w trybie BOOLEAN




                        Rysunek 6.39. To wyszukiwanie dotyczy wariantów dwóch różnych słów, z których jedno ma wyższy priorytet




                        210
Zaawansowany SQL i MySQL


                                               Wskazówki
                                                 W MySQL 5.1.7 wprowadzono jeszcze jeden
                                                 tryb wyszukiwań FULLTEXT: tryb języka
                                                 naturalnego. Jeśli nie wybierzesz innego trybu
                                                 (np. Boolean), to jest on trybem domyślnym.
                                                 Modyfikator WITH QUERY EXPANSION pozwala
                                                 zwiększyć liczbę zwracanych wyników.
    Optymalizacja bazy danych                    Zapytania z tym modyfikatorem wykonują
Efektywność działania bazy danych zależy         w rzeczywistości dwa wyszukiwania, ale zwracają
głównie od jej struktury i indeksów. Tworząc     jeden zbiór wyników. Drugie wyszukiwanie
bazę, powinieneś spróbować:                      bazuje na terminach wyszukanych dodatkowo
                                                 w najlepszych wynikach pierwszego
   Wybrać najlepszy silnik przechowywania.
                                                 wyszukiwania. Pozwala to znaleźć dodatkowe
   Używać jak najmniej pojemnego typu            rekordy, ale nie zawsze odpowiadają one
   danych dla każdej kolumny.                    początkowym kryteriom wyszukiwania.
   Definiować kolumny jako NOT NULL tam,
   gdzie to możliwe.
   Używać wartości całkowitych jako kluczy
   głównych.
   Uważnie definiować indeksy, wybierając
   odpowiedni typ oraz stosując je




                                                                                                   Wyszukiwanie FULLTEXT
   dla właściwych kolumn.
   Ograniczać indeksy do pewnej liczby
   znaków, jeśli to możliwe.
Oprócz tych wskazówek warto zastosować
dwie proste techniki optymalizacji baz
danych. Jednym ze sposobów poprawy
efektywności działania MySQL-a jest
wykonanie polecenia OPTIMIZE dla tabel.
Polecenie to usuwa wolne przestrzenie
i przywraca wysoką efektywność działania
tabel.
  OPTIMIZE TABLE tabela;
Wykonanie tego polecenia jest szczególnie
zalecane po modyfikacji tabeli za pomocą
polecenia ALTER.
Aby zwiększyć wydajność wykonywanego
zapytania, warto zrozumieć, w jaki sposób
serwer MySQL-a je przetwarza. W tym celu
należy posłużyć się słowem kluczowym
języka SQL o nazwie EXPLAIN. Informacje
na temat działania zapytań znajdziesz
w podręczniku MySQL-a.


                                                                                             211
Rozdział 6.


                         Wykonywanie transakcji                               Po zatwierdzeniu lub wycofaniu zapytań
                                                                              transakcja jest uznawana za zakończoną
                         Transakcja bazodanowa to seria zapytań               i MySQL wraca do trybu automatycznego
                         wykonywanych podczas jednej sesji. Przypuśćmy, zatwierdzania (ang. autocommit). Oznacza to,
                         że wstawiamy rekord do jednej tabeli, inny rekord że wszystkie zapytania są natychmiast
                         do drugiej tabeli, a potem wykonujemy aktualizację. realizowane. Aby rozpocząć następną
                         Bez transakcji każda operacja jest realizowana       transakcję, wystarczy ponownie wpisać START
                         natychmiast i nie można jej cofnąć. Jeśli użyjemy TRANSACTION.
                         transakcji, będziemy mogli ustawić punkt
                         początkowy i końcowy, a następnie zatwierdzić Trzeba wiedzieć, że niektórych typów transakcji
                         lub wycofać wszystkie zapytania (jeśli, na przykład, nie da się wycofać; dotyczy to w szczególności
                         zawiedzie jedno zapytanie, będzie można wycofać zapytań, które tworzą, modyfikują, opróżniają
                         wszystkie).                                          lub usuwają tabele albo tworzą lub usuwają
                                                                              bazy danych. Co więcej, wykonanie takiego
                         Transakcje są często potrzebne w interakcjach        zapytania skutkuje zatwierdzeniem
                         finansowych, nawet tak podstawowych jak przelew i zakończeniem bieżącej transakcji.
                         100 złotych z jednego konta na drugie. Proces ten
                         wydaje się prosty, ale w rzeczywistości składa się Powinieneś też pamiętać, że transakcje są
                         z kilku etapów:                                      specyficzne dla każdego połączenia. Zatem
                                                                              jeden użytkownik klienta mysql dokonuje
                             Potwierdzenia, że na pierwszym koncie znajduje innej transakcji niż użytkownik drugiego
                             się przynajmniej 100 złotych.                    klienta, a obie te transakcje są niezależne
                             Zmniejszenia stanu pierwszego konta              od realizowanych przez skrypt PHP.
Wykonywanie transakcji




                             o 100 złotych.                                   To powiedziawszy, zaprezentuję bardzo prosty
                               Zwiększenia stanu drugiego konta o 100 złotych.   przykład użycia transakcji w kliencie mysql.
                                                                                 W rozdziale 17. pokażę, jak realizować
                               Sprawdzenia, czy udało się zwiększyć stan         transakcje z wykorzystaniem skryptów PHP.
                               drugiego konta.
                         Jeśli którakolwiek z tych operacji się nie powiedzie,
                         należy cofnąć je wszystkie. Jeśli na przykład nie uda
                         się umieścić pieniędzy na drugim koncie, powinny
                         one wrócić na pierwsze. Odbywa się to do momentu,
                         w którym uda się przeprowadzić całą transakcję.
                         Aby korzystać z transakcji w MySQL-u, trzeba
                         posługiwać się tabelami InnoDB (lub silnikiem
                         tego typu). W celu rozpoczęcia nowej transakcji
                         w kliencie mysql należy wpisać:
                           START TRANSACTION;

                         Na zakończenie transakcji należy wydać instrukcję
                         COMMIT, aby zatwierdzić wszystkie zapytania,
                         albo ROLLBACK, aby je wycofać.




                         212
Zaawansowany SQL i MySQL


Aby wykonać transakcję,                            Oczywiście trudno uznać to za kompletny
należy wykonać poniższe czynności:                 projekt tabeli czy bazy danych. Zasady
                                                   normalizacji nakazywałyby rozdzielić imię
 1. Uruchomić klienta mysql i wybrać bazę
                                                   i nazwisko użytkownika na dwie kolumny,
   danych test.
                                                   a nawet umieścić je w innej tabeli. Jednakże
   Ponieważ jest to tylko przykład,                tabela ta w zupełności wystarczy do naszych
   wykorzystam hipotetyczną bazę danych test.      celów.
 2. Utworzyć nową tabelę accounts                  Najważniejszym aspektem definicji tabeli jest
   (patrz rysunek 6.40).                           określenie mechanizmu InnoDB, który obsługuje
     CREATE TABLE accounts (
                                                   transakcje.
       id INT UNSIGNED NOT NULL                  3. Wypełnić tabelę danymi.
         AUTO_INCREMENT,
       name VARCHAR(40) NOT NULL,                    INSERT INTO accounts (name, balance)
       balance DECIMAL(10,2) NOT NULL                VALUES ('Beata Piechota', 5460.30),
         DEFAULT 0.0,                                ('Dawid Wójcik', 909325.24),
       PRIMARY KEY (id))                             ('Ilona Machnik', 892.00);
       ENGINE=InnoDB;
                                                   Można użyć dowolnie wybranych nazwisk
                                                   i wartości. Należy zauważyć, że MySQL
                                                   automatycznie zatwierdzi to zapytanie,
                                                   ponieważ nie została jeszcze rozpoczęta
                                                   żadna transakcja.




                  Rysunek 6.40. Nowa tabela utworzona w bazie danych test posłuży                   Wykonywanie transakcji
                  do zademonstrowania transakcji




                                                                                              213
Rozdział 6.


                          4. Rozpocząć transakcję i pobrać bieżącą zawartość
                               tabeli (patrz rysunek 6.41).
                                 START TRANSACTION;
                                 SELECT * FROM accounts;

                          5. Podjąć 100 złotych z konta Dawida Wójcika
                               (albo dowolnego innego użytkownika).
                                 UPDATE accounts                                   Rysunek 6.41. Rozpoczęto transakcję i wyświetlono
                                 SET balance=(balance-100)                         wszystkie rekordy znajdujące się w tabeli
                                 WHERE id=2;

                               Instrukcja UPDATE, odrobina matematyki
                               i klauzula WHERE pozwalają zmniejszyć stan
                               konta o 100 złotych. Choć MySQL informuje,
                               że zmodyfikowany został jeden wiersz, efekt
                               nie będzie trwały, dopóki transakcja nie zostanie
                               zatwierdzona.
                          6. Wpłacić 100 złotych na konto Beaty Piechoty:
                                 UPDATE accounts
                                 SET balance=(balance+100)
                                 WHERE id=1;
                                                                                   Rysunek 6.42. Wykonano dwa zapytania
                               Jest to przeciwieństwo operacji wykonanej           i wyświetlono wyniki
                               w etapie 5., co odzwierciedla przelewanie
Wykonywanie transakcji




                               100 złotych z jednego konta na drugie.
                          7. Sprawdzić wyniki (patrz rysunek 6.42).
                                 SELECT * FROM accounts;

                               Jak widać na rysunku, na jednym koncie
                               jest teraz o 100 złotych więcej, a na drugim
                               o 100 złotych mniej niż na początku
                               (patrz rysunek 6.41).




                         214
Zaawansowany SQL i MySQL


                                          8. Wycofać transakcję.
                                               ROLLBACK;

                                             Aby zademonstrować wycofywanie transakcji,
                                             unieważniam wykonane wcześniej zapytania.
                                             Instrukcja ROLLBACK przywraca bazę danych
                                             do stanu sprzed rozpoczęcia transakcji. Instrukcja
                                             ta kończy jednocześnie transakcję, przełączając
                                             MySQL-a z powrotem do trybu automatycznego
                                             zatwierdzania.
Rysunek 6.43. Ponieważ użyto instrukcji   9. Sprawdzić wyniki (patrz rysunek 6.43).
ROLLBACK, wykonane wcześniej zapytania         SELECT * FROM accounts;
zostały wycofane
                                             Zapytanie powinno zwrócić zawartość tabeli
                                             sprzed rozpoczęcia transakcji.
                                          10. Powtórzyć etapy 4. – 6.

                                             Aby sprawdzić, co się stanie w razie
                                             zatwierdzenia transakcji, należy ponownie
                                             wykonać dwa zapytania UPDATE. Należy pamiętać
                                             o rozpoczęciu nowej transakcji, ponieważ
                                             w przeciwnym razie zapytania zostaną




                                                                                                  Wykonywanie transakcji
                                             automatycznie zatwierdzone!
                                          11. Zatwierdzić transakcję i sprawdzić wyniki
                                             (patrz rysunek 6.44).
                                               COMMIT;
Rysunek 6.44. Instrukcja COMMIT                SELECT * FROM accounts;
utrwala rezultaty transakcji
                                             Po wydaniu instrukcji COMMIT transakcja zostanie
                                             zatwierdzona, co oznacza, że wszystkie zmiany
                                             staną się trwałe. Instrukcja ta jednocześnie
                                             kończy transakcję, przełączając MySQL-a
                                             z powrotem do trybu automatycznego
                                             zatwierdzania.




                                                                                           215
Rozdział 6.


                         Wskazówki
                               Jedną z największych zalet transakcji jest to,
                               że zapewniają one ochronę przed zdarzeniami
                               losowymi, takimi jak awaria serwera. Transakcja
                               jest albo w całości zatwierdzana,
                               albo ignorowana.
                               Aby wyłączyć tryb automatycznego
                               zatwierdzania w serwerze MySQL-a,
                               należy wpisać:
                                 SET AUTOCOMMIT=0;

                               Nie trzeba będzie wówczas wydawać instrukcji
                               START TRANSACTION, a wszystkie wykonane
                               zapytania zostaną zrealizowane dopiero
                               po wpisaniu instrukcji COMMIT (albo użyciu
                               zapytania CREATE, ALTER itp.).
                               W transakcjach można tworzyć punkty zapisu:
                                 SAVEPOINT nazwa_punktu_zapisu;

                               Funkcja ta umożliwia wycofanie transakcji
                               do określonego punktu zapisu:
Wykonywanie transakcji




                                 ROLLBACK TO SAVEPOINT nazwa_punktu_zapisu;




                         216

More Related Content

PDF
Prawo prasowe. Komentarz. Wydanie 3 - ebook
PDF
Kodeks postępowania karnego oraz ustawa o świadku koronnym - ebook
PDF
Ergonomia książka
PDF
J.KORNAS, Obowiązek lojalności akcjonariusza w spółce akcyjnej
PDF
Triangledigger Thesis
PDF
Sankcje w prawie administracyjnym i procedura ich wymierzania - ebook
PDF
Pompa strzykawkowa Alaris PK, instrukcja obsługi
PDF
Kpd 25 10_2012 międzyresortowe
Prawo prasowe. Komentarz. Wydanie 3 - ebook
Kodeks postępowania karnego oraz ustawa o świadku koronnym - ebook
Ergonomia książka
J.KORNAS, Obowiązek lojalności akcjonariusza w spółce akcyjnej
Triangledigger Thesis
Sankcje w prawie administracyjnym i procedura ich wymierzania - ebook
Pompa strzykawkowa Alaris PK, instrukcja obsługi
Kpd 25 10_2012 międzyresortowe

What's hot (20)

PDF
Bezstronność sądu i jej gwarancje w polskim procesie karnym
PDF
Obywatel w post-cywilnym-calosc (1)
PDF
Prawo konkurencji a regulacja sektorowa - ebook
PDF
Ustawa o działalności pożytku publicznego i o wolontariacie. Komentarz - ebook
PDF
Proces karny. część szczególna - ebook
PDF
Od zera-do-ecedeela-cz-4
PDF
Ppej 28 01 2014
PDF
Kodeks pracy - ebook
PDF
Wadliwa spółka partnerska - ebook
PDF
Cywilnoprawna ochrona dziecka poczętego a stosowanie procedur medycznych - ebook
PDF
Środki odwoławcze w postępowaniu cywilnym - ebook
PDF
Ochrona dóbr osobistych w zatrudnieniu - ebook
DOC
Helion.2005.php.i.my sql.tworzenie.stron.www.vademecum.profesjonalisty.wyd3
PDF
Przestępczość przeciwko zabytkom archeologicznym. Problematyka prawno krymina...
PDF
Ponadnarodowość w systemie politycznym unii europejskiej - ebook
PDF
Psychologia Wywieranie Wplywu Darmowy Fragment
PDF
Instrukcja obslugi pompy objetosciowej Medima P2
PDF
Kodeks karny. Praktyczny komentarz - ebook
PDF
Zasady uspokajania ruchu
PDF
Biala ksiega
Bezstronność sądu i jej gwarancje w polskim procesie karnym
Obywatel w post-cywilnym-calosc (1)
Prawo konkurencji a regulacja sektorowa - ebook
Ustawa o działalności pożytku publicznego i o wolontariacie. Komentarz - ebook
Proces karny. część szczególna - ebook
Od zera-do-ecedeela-cz-4
Ppej 28 01 2014
Kodeks pracy - ebook
Wadliwa spółka partnerska - ebook
Cywilnoprawna ochrona dziecka poczętego a stosowanie procedur medycznych - ebook
Środki odwoławcze w postępowaniu cywilnym - ebook
Ochrona dóbr osobistych w zatrudnieniu - ebook
Helion.2005.php.i.my sql.tworzenie.stron.www.vademecum.profesjonalisty.wyd3
Przestępczość przeciwko zabytkom archeologicznym. Problematyka prawno krymina...
Ponadnarodowość w systemie politycznym unii europejskiej - ebook
Psychologia Wywieranie Wplywu Darmowy Fragment
Instrukcja obslugi pompy objetosciowej Medima P2
Kodeks karny. Praktyczny komentarz - ebook
Zasady uspokajania ruchu
Biala ksiega
Ad

Viewers also liked (7)

PDF
Marketing Internetowy W Praktyce
PDF
30. Montowanie i badanie instalacji do odbioru telewizji satelitarnej
PDF
Informacja zawodowa
PDF
PPT
PDF
Bachelor Thesis
PDF
Periodyzacja taktyczna
Marketing Internetowy W Praktyce
30. Montowanie i badanie instalacji do odbioru telewizji satelitarnej
Informacja zawodowa
Bachelor Thesis
Periodyzacja taktyczna
Ad

Similar to PHP6 i MySQL 5. Dynamiczne strony WWW. Szybki start (20)

PDF
Ajax, JavaScript i PHP. Intensywny trening
PDF
PHP i MySQL. Dynamiczne strony WWW. Szybki start. Wydanie II
PDF
Pozycjonowanie i optymalizacja stron WWW. Jak się to robi. Wydanie II poprawi...
PDF
Witryny nie do ukrycia. Jak zbudować stronę, którą znajdzie każda wyszukiwarka
PDF
PHP i MySQL. Dynamiczne strony WWW. Szybki start
PDF
Po prostu PHP. Techniki zaawansowane
PDF
Serwer SQL 2008. Administracja i programowanie
PDF
Kurs tworzenia stron internetowych
PDF
Pajączek 5 NxG. Oficjalny podręcznik
PDF
Java. Techniki zaawansowane. Wydanie VIII
PDF
Oracle Database 11g. Programowanie w języku PL/SQL
PDF
Oracle Discoverer
PDF
MySQL. Szybki start
PDF
Godzina dziennie z Web Analytics. Stwórz dobrą strategię e-marketingową
PDF
Po prostu FrontPage 2003 PL
PDF
Microsoft Visual Studio 2008. Księga eksperta
PDF
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
PDF
PHP, Microsoft IIS i SQL Server. Projektowanie i programowanie baz danych
PDF
CATIA V5. Podstawy budowy modeli autogenerujących
PDF
Visual Basic 2008. Warsztat programisty
Ajax, JavaScript i PHP. Intensywny trening
PHP i MySQL. Dynamiczne strony WWW. Szybki start. Wydanie II
Pozycjonowanie i optymalizacja stron WWW. Jak się to robi. Wydanie II poprawi...
Witryny nie do ukrycia. Jak zbudować stronę, którą znajdzie każda wyszukiwarka
PHP i MySQL. Dynamiczne strony WWW. Szybki start
Po prostu PHP. Techniki zaawansowane
Serwer SQL 2008. Administracja i programowanie
Kurs tworzenia stron internetowych
Pajączek 5 NxG. Oficjalny podręcznik
Java. Techniki zaawansowane. Wydanie VIII
Oracle Database 11g. Programowanie w języku PL/SQL
Oracle Discoverer
MySQL. Szybki start
Godzina dziennie z Web Analytics. Stwórz dobrą strategię e-marketingową
Po prostu FrontPage 2003 PL
Microsoft Visual Studio 2008. Księga eksperta
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
PHP, Microsoft IIS i SQL Server. Projektowanie i programowanie baz danych
CATIA V5. Podstawy budowy modeli autogenerujących
Visual Basic 2008. Warsztat programisty

More from Wydawnictwo Helion (20)

PDF
Tworzenie filmów w Windows XP. Projekty
PDF
Blog, więcej niż internetowy pamiętnik
PDF
Access w biurze i nie tylko
PDF
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
PDF
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
PDF
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
PDF
Makrofotografia. Magia szczegółu
PDF
Windows PowerShell. Podstawy
PDF
Java. Efektywne programowanie. Wydanie II
PDF
JavaScript. Pierwsze starcie
PDF
PowerPoint 2007 PL. Seria praktyk
PDF
Excel 2007 PL. Seria praktyk
PDF
Access 2007 PL. Seria praktyk
PDF
Word 2007 PL. Seria praktyk
PDF
Serwisy społecznościowe. Budowa, administracja i moderacja
PDF
AutoCAD 2008 i 2008 PL
PDF
Bazy danych. Pierwsze starcie
PDF
Inventor. Pierwsze kroki
PDF
USB. Praktyczne programowanie z Windows API w C++
PDF
Rewizor GT. Prowadzenie ewidencji księgowej
Tworzenie filmów w Windows XP. Projekty
Blog, więcej niż internetowy pamiętnik
Access w biurze i nie tylko
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Makrofotografia. Magia szczegółu
Windows PowerShell. Podstawy
Java. Efektywne programowanie. Wydanie II
JavaScript. Pierwsze starcie
PowerPoint 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktyk
Access 2007 PL. Seria praktyk
Word 2007 PL. Seria praktyk
Serwisy społecznościowe. Budowa, administracja i moderacja
AutoCAD 2008 i 2008 PL
Bazy danych. Pierwsze starcie
Inventor. Pierwsze kroki
USB. Praktyczne programowanie z Windows API w C++
Rewizor GT. Prowadzenie ewidencji księgowej

PHP6 i MySQL 5. Dynamiczne strony WWW. Szybki start

  • 1. PHP6 i MySQL 5. Dynammiczne strony www. Szybki start Autor: Larry Ullman T³umaczenie: Jaromir Senczyk ISBN: 978-83-246-1723-4 Tytu³ orygina³u: PHP 6 and MySQL 5 for Dynamic Web Sites: Visual QuickPro Guide Format: 170x230, stron: 640 Poznaj mo¿liwoœci PHP6 oraz MySQL 5 i twórz dynamiczne strony WWW • Jak utworzyæ podstawowy skrypt PHP? • Jak korzystaæ z wielowymiarowych tablic? • Jak budowaæ bazy danych? Ka¿da funkcjonalna i atrakcyjna dla u¿ytkowników strona internetowa musi byæ na bie¿¹co aktualizowana, a umieszczone na niej interesuj¹ce informacje powinny byæ ³atwo dostêpne. Najpopularniejsze narzêdzia typu open source, s³u¿¹ce do tworzenia dynamicznych witryn, to jêzyk PHP i system zarz¹dzania relacyjnymi bazami danych MySQL. Oba te narzêdzia oferuj¹ wysok¹ wydajnoœæ, przenoœnoœæ i niezawodnoœæ. Wœród wielu ogromnych mo¿liwoœci oraz zalet PHP i MySQL maj¹ tak¿e tak¹, ¿e sprawne pos³ugiwanie siê nimi nie jest zbyt skomplikowane nawet dla pocz¹tkuj¹cych. Ksi¹¿ka „PHP6 i MySQL 5. Dynamiczne strony WWW. Szybki start” zawiera precyzyjny opis czynnoœci oraz bogato ilustrowane zrzutami ekranu niezbêdne wskazówki i wyjaœnienia, u³atwiaj¹ce samodzielne zbudowanie dynamicznej strony internetowej. Dziêki temu podrêcznikowi nauczysz siê wyszukiwaæ i usuwaæ b³êdy w skryptach PHP, tworzyæ formularze w jêzyku HTML oraz zapobiegaæ atakom na Twoje witryny. Poznasz tak¿e podstawowe i zaawansowane techniki tworzenia ró¿nych aplikacji (na przyk³ad stron wielojêzycznych lub obs³uguj¹cych fora dyskusyjne). • PHP i MySQL • Tworzenie formularza w jêzyku HTML • Tablice i ³añcuchy • Tworzenie i wywo³ywanie w³asnych funkcji • Wype³nianie baz danych • Zabezpieczenia • Stosowanie modyfikatorów • Szyfrowanie danych • Tworzenie uniwersalnych witryn • Budowanie strony domowej • Wielojêzyczna strona WWW • Tworzenie kont u¿ytkowników i nadawanie uprawnieñ Szybko i ³atwo naucz siê tworzyæ funkcjonalne oraz bezpieczne witryny internetowe
  • 2. Spis treści Wprowadzenie 9 Czym są dynamiczne strony WWW? ................................................................... 10 Co będzie Ci potrzebne? ....................................................................................... 16 O tej książce ........................................................................................................... 17 Rozdział 1. Wprowadzenie do PHP 19 Podstawy składni.................................................................................................... 20 Przesyłanie danych do przeglądarki internetowej ............................................... 24 Wstawianie komentarzy......................................................................................... 28 Co to są zmienne? .................................................................................................. 32 Łańcuchy ................................................................................................................ 36 Łączenie łańcuchów............................................................................................... 39 Spis treści Liczby ..................................................................................................................... 41 Stałe ........................................................................................................................ 45 Apostrof kontra cudzysłów .................................................................................... 48 Rozdział 2. Programowanie w PHP 51 Tworzenie formularza w języku HTML ............................................................... 52 Obsługa formularza HTML................................................................................... 56 Wyrażenia warunkowe i operatory ....................................................................... 60 Weryfikacja danych pochodzących z formularza ................................................. 64 Co to są tablice? ..................................................................................................... 70 Pętle for i while ...................................................................................................... 88 Rozdział 3. Tworzenie dynamicznych stron WWW 91 Wykorzystywanie plików zewnętrznych .............................................................. 92 Wyświetlanie i obsługa formularza przez jeden skrypt ....................................... 102 Tworzenie formularzy z pamięcią ....................................................................... 107 Tworzenie i wywoływanie własnych funkcji ...................................................... 110 Rozdział 4. Wprowadzenie do MySQL 125 Elementy bazy danych i ich nazwy..................................................................... 126 Wybór typu kolumny ........................................................................................... 128 Wybór innych właściwości kolumn .................................................................... 132 Korzystanie z serwera MySQL-a ........................................................................ 134 5
  • 3. Spis treści Rozdział 5. Wprowadzenie do SQL 141 Tworzenie baz danych i tabel.............................................................................. 142 Wprowadzanie rekordów..................................................................................... 145 Wybieranie danych .............................................................................................. 149 Wyrażenia warunkowe ........................................................................................ 151 Stosowanie LIKE i NOT LIKE .......................................................................... 154 Sortowanie wyników zapytania ........................................................................... 156 Ograniczanie wyników zapytania........................................................................ 158 Uaktualnianie danych .......................................................................................... 160 Usuwanie danych ................................................................................................. 162 Funkcje ................................................................................................................. 164 Rozdział 6. Zaawansowany SQL i MySQL 175 Projekt bazy danych............................................................................................. 176 Złączenia............................................................................................................... 191 Grupowanie wyników zapytania ......................................................................... 196 Indeksy ................................................................................................................. 198 Stosowanie różnych typów tabeli........................................................................ 203 Wyszukiwanie FULLTEXT ................................................................................ 206 Spis treści Wykonywanie transakcji...................................................................................... 212 Rozdział 7. Obsługa i usuwanie błędów 217 Ogólne typy błędów i ich usuwanie.................................................................... 218 Wyświetlanie błędów PHP.................................................................................. 224 Sterowanie raportowaniem błędów PHP ........................................................... 226 Tworzenie własnych funkcji obsługi błędów ..................................................... 229 Techniki usuwania błędów z PHP ...................................................................... 234 Techniki usuwania błędów SQL i MySQL ........................................................ 238 Rozdział 8. PHP i MySQL 241 Modyfikacja szablonu .......................................................................................... 242 Łączenie się z MySQL-em i wybieranie bazy.................................................... 244 Wykonywanie prostych zapytań.......................................................................... 248 Odczytywanie wyników zapytania ...................................................................... 257 Bezpieczeństwo zapytań...................................................................................... 261 Zliczanie zwróconych rekordów ......................................................................... 267 Uaktualnianie rekordów w PHP ......................................................................... 269 Rozdział 9. Tworzenie aplikacji internetowych 277 Przekazywanie wartości do skryptu..................................................................... 278 Stosowanie ukrytych pól formularza................................................................... 282 Edycja istniejących rekordów ............................................................................. 288 6
  • 4. Spis treści Stronicowanie wyników zapytań......................................................................... 295 Wyświetlanie tabel z możliwością sortowania.................................................... 303 Rozdział 10. Tworzenie aplikacji internetowych 309 Wysyłanie poczty elektronicznej ........................................................................ 310 Funkcje daty i czasu............................................................................................. 316 Obsługa przesyłania plików................................................................................. 320 Skrypty PHP i JavaScript .................................................................................... 333 Nagłówki HTTP ................................................................................................... 340 Rozdział 11. Sesje i „ciasteczka” 345 Strona logowania .................................................................................................. 346 Funkcje logowania ............................................................................................... 349 Posługiwanie się ciasteczkami............................................................................. 354 Sesje ...................................................................................................................... 367 Zwiększanie bezpieczeństwa sesji ...................................................................... 376 Rozdział 12. Zabezpieczenia 379 Zapobieganie spamowi ........................................................................................ 380 Spis treści Walidacja danych według typu ........................................................................... 387 Zapobieganie atakom XSS ................................................................................... 392 Zapobieganie wstrzykiwaniu poleceń SQL........................................................ 395 Szyfrowanie i bazy danych .................................................................................. 401 Rozdział 13. Wyrażenie regularne Perl 407 Skrypt testujący.................................................................................................... 408 Definiowanie prostych wzorców......................................................................... 412 Stosowanie kwantyfikatorów ............................................................................... 415 Klasy znaków ........................................................................................................ 418 Wyszukiwanie wszystkich dopasowań................................................................ 421 Stosowanie modyfikatorów.................................................................................. 425 Dopasowywanie i zastępowanie wzorców.......................................................... 427 Rozdział 14. Tworzenie uniwersalnych witryn 431 Zbiory znaków i kodowanie................................................................................. 432 Tworzenie wielojęzycznych stron WWW .......................................................... 434 Unicode w PHP ................................................................................................... 438 Uporządkowanie zbioru znaków w PHP ............................................................ 442 Transliteracja w PHP........................................................................................... 445 Języki i MySQL.................................................................................................... 448 Strefy czasowe i MySQL ..................................................................................... 452 Lokalizatory .......................................................................................................... 455 7
  • 5. Spis treści Rozdział 15. Forum dyskusyjne — przykład 459 Baza danych.......................................................................................................... 460 Szablony................................................................................................................ 469 Strona domowa..................................................................................................... 478 Strona forum......................................................................................................... 479 Strona wątku......................................................................................................... 484 Wstawianie wiadomości....................................................................................... 489 Rozdział 16. Rejestracja użytkowników — przykład 501 Tworzenie szablonu ............................................................................................. 502 Skrypty konfiguracyjne........................................................................................ 508 Tworzenie strony domowej ................................................................................. 516 Rejestracja ............................................................................................................ 518 Aktywacja konta ................................................................................................... 527 Logowanie i wylogowywanie się......................................................................... 531 Zarządzanie hasłami............................................................................................. 537 Rozdział 17. Sklep internetowy — przykład 547 Tworzenie bazy danych ....................................................................................... 548 Spis treści Część administracyjna aplikacji .......................................................................... 554 Tworzenie szablonu części publicznej aplikacji................................................. 571 Katalog produktów............................................................................................... 575 Koszyk................................................................................................................... 587 Rejestrowanie zamówień ..................................................................................... 597 Dodatek A Instalacja 605 Instalacja w systemie Windows .......................................................................... 606 Definiowanie uprawnień MySQL....................................................................... 609 Testowanie instalacji............................................................................................ 613 Konfigurowanie PHP........................................................................................... 616 Skorowidz 619 8
  • 6. Zaawansowany SQL i MySQL 6 Rozdział 6. Zaawansowany SQL i MySQL Rozdział ten zaczyna się w miejscu, w którym ostatni się kończył. Omówię w nim bardziej zaawansowane zagadnienia dotyczące SQL-a i MySQL-a. Poznałeś już podstawy obu tych technologii i z pewnością wystarczą Ci one do realizacji wielu projektów, ale dopiero ich bardziej wyszukane możliwości wyniosą Twe aplikacje internetowe na wyższy poziom. Zacznę od szczegółowego omówienia procesu projektowania bazy danych, opierając się na przykładzie systemu zarządzania forum. Doprowadzi nas to oczywiście do tematu złączeń, będących integralną częścią każdej relacyjnej bazy danych. Następnie będę opisywał kolejną kategorię funkcji wbudowanych MySQL-a używanych do grupowania wyników zapytań. Na zakończenie przejdę do bardziej zaawansowanych zagadnień. Powiem o indeksach, nauczę Cię zmieniać strukturę istniejących tabel oraz omówię typy tabel dostępne w MySQL-u. Rozdział zakończę omówieniem dwóch dodatkowych możliwości MySQL-a: przeszukiwania tekstów i transakcji. Zaawansowany SQL i MySQL 175
  • 7. Rozdział 6. Projekt bazy danych W moim przykładowym systemie będę chciał stworzyć forum, na którym użytkownicy mogą Pierwsze, co musisz zrobić, gdy pracujesz z systemem zamieszczać swoje opinie i odpowiadać innym zarządzania relacyjnymi bazami danych, takim jak internautom. Aby korzystać z forum, użytkownik MySQL, to utworzyć strukturę bazy (zwaną również będzie musiał się zarejestrować, a następnie schematem bazy danych). Projektowanie bazy danych uwierzytelnić za pomocą kombinacji nazwy i hasła. lub inaczej modelowanie danych to niezbędny etap Przewiduję również możliwość istnienia wielu gwarantujący długotrwałe i bezproblemowe zarządzanie forów poświęconych różnym tematom. W tabeli Twoimi informacjami. W procesie zwanym normalizacją 6.1 pokazałem, jak wygląda przykładowy rekord. eliminuje się niepotrzebne powtórzenia informacji Baza danych będzie nosić nazwę forum. i inne problemy, które zagrażają spójności danych. Wskazówki Dzięki technikom, które poznasz w tym rozdziale, Twoje bazy będą wydajne i niezawodne. Jeden Istnieje bardzo dobra metoda na określenie, z przykładów, które zaprezentuję — forum, na którym jakiego rodzaju informacje powinny się użytkownicy mogą wymieniać się opiniami — będzie znaleźć w bazie danych. Wystarczy, intensywnie wykorzystywany dopiero w rozdziale 15., że zastanowisz się, jakiego rodzaju pytania „Forum dyskusyjne — przykład”. Jednak omówione o dane będą zadawane przez użytkowników przeze mnie zasady normalizacji odnoszą się i jakie dane będą musiały się znaleźć do wszystkich aplikacji bazodanowych, jakie możesz w odpowiedziach. utworzyć. (Przykład bazy sitename używany Nauka normalizacji może sprawić Ci trudności, w poprzednich dwóch rozdziałach został poprawnie jeśli niepotrzebnie skoncentrujesz się na zaprojektowany również z punktu widzenia normalizacji, szczegółach. Każda z postaci normalnych jest ale zagadnienie to nie zostało jeszcze omówione.) zdefiniowana w dość skomplikowany sposób, a próba przełożenia tych definicji na język Projekt bazy danych Normalizacja niefachowy może być myląca. Dlatego radzę Proces normalizacji został wymyślony na początku lat Ci, abyś podczas lektury omówienia postaci siedemdziesiątych przez E.F. Codda, naukowca z firmy normalnych skoncentrował się na ogólnym IBM, który wymyślił też relacyjne bazy danych. Tego obrazie zmian zachodzących w schemacie rodzaju bazy to nic innego jak tylko zbiór danych bazy danych. Po zakończeniu normalizacji ułożonych w pewien określony sposób. Istnieje szereg i otrzymaniu końcowej postaci bazy danych tak zwanych postaci normalnych (NF, z ang. Normal cały proces powinien stać się dla Ciebie Form), które ułatwiają definiowanie struktury danych. wystarczająco zrozumiały. W tym rozdziale omówię pierwsze trzy z nich, Tabela 6.1. Przykładowy rekord pokazujący, jakiego ponieważ w większości przypadków są one w pełni rodzaju informacje chcę przechowywać w mojej wystarczające. bazie danych Zanim zaczniesz normalizować swoją bazę danych, Przykładowe dane forum musisz określić, jakie funkcje będzie pełniła Twoja Element Przykład aplikacja. Być może będziesz musiał w tym celu username janek porozmawiać z klientem lub samodzielnie zastanowić password haslo się nad tym zagadnieniem. W każdym razie struktura actual name Jan Kowalski bazy danych zależy od sposobu, w jaki aplikacja będzie user email jank@example.com odwoływała się do zgromadzonych w niej informacji. forum MySQL Na tym etapie będziesz więc potrzebował raczej kartki message subject Pytanie na temat normalizacji i ołówka niż MySQL-a. Oczywiście, w ten sposób message body Nie rozumiem jednej rzeczy. Dla drugiej projektuje się wszystkie relacyjne bazy danych, postaci normalnej (2NF) podano... nie tylko te działające w systemie MySQL. message date 2 lutego 2008 12:20 176
  • 8. Zaawansowany SQL i MySQL Klucze Baza danych forum składa się w zasadzie tylko z jednej prostej tabeli (tabela 6.1), ale zanim rozpocznę proces W rozdziale 4., „Wprowadzenie do MySQL-a”, normalizacji, chcę utworzyć w niej przynajmniej jeden wspominałem już, że klucze są integralną częścią klucz główny (klucze obce pojawią się w następnych znormalizowanych baz danych. Spotkasz się krokach). z dwoma rodzajami kluczy, głównymi i obcymi. Klucz główny to unikatowy identyfikator, który Aby przypisać klucz główny: podlega pewnym ściśle określonym regułom. Musi on: 1. Poszukaj pól, które spełniają wszystkie trzy warunki określone dla kluczy głównych. Zawsze mieć jakąś wartość (inną niż NULL). W naszym przykładzie (tabela 6.1) żadna z kolumn Mieć stałą wartość (taką, która nigdy nie ulega nie spełnia kryteriów klucza głównego. Nazwa zmianie). użytkownika i adres e-mail są unikalne dla każdego Mieć inną wartość dla każdego rekordu użytkownika forum, ale nie dla każdego rekordu w tabeli. bazy danych (ten sam użytkownik może umieszczać wiele wiadomości na forum). Również ten sam Najlepszym, z życia wziętym przykładem klucza temat wiadomości może występować wiele razy. głównego jest numer ubezpieczenia społecznego Tekst wiadomości będzie prawdopodobnie zawsze przydzielany obywatelom USA. Każdy ma tam unikalny, ale może się zmieniać na skutek własny, niezmienny, unikatowy numer polisy. późniejszych poprawek, tym samym naruszając Ułatwia to identyfikowanie osób. Wkrótce jedno z kryteriów wyboru klucza głównego. przekonasz się, że wielokrotnie sam będziesz tworzył we wszystkich tabelach klucze główne. 2. Jeżeli nie istnieje żaden logiczny kandydat na klucz Jest to po prostu dobra praktyka projektowa. główny — wprowadź go! (tabela 6.2). Projekt bazy danych Drugi rodzaj kluczy stanowią klucze obce. Sytuacja, w której musisz sam utworzyć klucz Reprezentują one w tabeli B klucze główne główny, ponieważ żadne z istniejących pól nie tabeli A. Jeżeli masz na przykład bazę danych nadaje się do pełnienia tej roli, występuje dość filmy, w której występują tabele film i reżyser, często. W tym konkretnym przykładzie utworzę to klucz główny tabeli reżyser będzie pełnił pole message ID. rolę klucza obcego w tabeli film. Już niedługo zobaczysz, jak to wszystko działa w praktyce. Wskazówki Stosuję się do reguły, w myśl której w nazwach Tabela 6.2. Dodałem do tabeli klucz główny, dzięki czemu kluczy głównych powinna wystąpić przynajmniej będę mógł łatwo odwoływać się do rekordów część nazwy tabeli (np. message) i przyrostek id. Baza danych forum Niektórzy projektanci dodają również skrót pk (ang. primary key — klucz główny). Element Przykład message ID 1 MySQL zezwala na stosowanie w każdej tabeli username janek tylko jednego klucza głównego, choć możesz oprzeć password haslo go na kilku kolumnach (oznacza to, że kombinacja actual name Jan Kowalski tych kolumn musi być unikatowa). user email jank@example.com Najlepiej byłoby, gdyby Twój klucz główny forum MySQL był zawsze liczbą całkowitą, ponieważ pozwala message subject Pytanie na temat normalizacji to MySQL-owi osiągnąć najwyższą możliwą message body Nie rozumiem jednej rzeczy. Dla drugiej wydajność. postaci normalnej (2NF) podano... message date 2 lutego 2008 12:20 177
  • 9. Rozdział 6. Zależności Wskazówki Mówiąc o zależnościach w bazach danych mam Modelowanie baz danych rządzi się na myśli to, w jaki sposób dane z jednej tabeli są pewnymi regułami. Istnieje określona powiązane z danymi występującymi w drugiej. konwencja reprezentowania struktury Zależności między dwiema tabelami mogą bazy (zostanie ona tutaj zachowana). przybierać postać jeden do jednego, jeden do wielu Na rysunku 6.1 pokazałem symbole trzech lub wiele do wielu. (Dwie tabele tej samej bazy rodzajów zależności. danych mogą być również wcale niepowiązane). Proces projektowania bazy danych prowadzi O zależności „jeden do jednego” mówimy wtedy, do powstania diagramu zależności między gdy jeden i tylko jeden element tabeli A odnosi się encjami (ERD), na którym występują do jednego i tylko jednego elementu tabeli B prostokąty reprezentujące tabele oraz (np. każdy mieszkaniec USA ma tylko jeden numer symbole z rysunku 6.1. ubezpieczenia społecznego, a każdy numer polisy Istnieje wiele programów służących jest przyporządkowany tylko do jednego obywatela. do tworzenia schematów baz danych. Nikt nie może mieć dwóch polis, podobnie jak Jednym z nich jest MySQL Workbench żaden numer ubezpieczenia nie może odnosić się (www.mysql.com). do dwóch osób). Termin „relacyjny” w określeniu „system Zależność „jeden do wielu” występuje wtedy, zarządzania relacyjnymi bazami danych” gdy jakiś element tabeli A może odnosić się do kilku odnosi się do tabel, które nazywa się różnych elementów tabeli B. Na przykład, relacjami. określenia mężczyzna i kobieta mogą być używane w odniesieniu do wielu osób, ale każdy człowiek Projekt bazy danych może mieć tylko jedną płeć. Jest to najczęściej występująca zależność między tabelami w znormalizowanych bazach danych. Istnieje też zależność „wiele do wielu”, w której kilka elementów tabeli A może odnosić się do kilku elementów tabeli B. Na przykład rekord płyta może zawierać piosenki wykonywane przez różnych artystów, a każdy artysta może mieć na swoim koncie kilka płyt. W swoich projektach powinieneś unikać tego typu zależności, ponieważ prowadzą one do problemów ze spójnością danych i sprzyjają ich Rysunek 6.1. Pokazane tu symbole często spotyka powielaniu. Zamiast zależności „wiele do wielu” się na diagramach strukturalnych. Opisują one stworzysz tabelę pośrednią, dzięki której zależność zależności występujące między tabelami „wiele do wielu” zostanie rozbita na dwie zależności „jeden do wielu”. Temat zależności jest w pewien sposób związany z zagadnieniem kluczy, ponieważ klucze zdefiniowane w jednej tabeli odwołują się zazwyczaj do pól występujących w innych tabelach. 178
  • 10. Zaawansowany SQL i MySQL Pierwsza postać normalna Na przykład tabela zawierająca pole, w którym można umieścić kilka numerów telefonów (domowy, Jak już powiedziałem wcześniej, normalizacja komórkowy, numer faksu itd.) nie jest zgodna bazy danych jest procesem dostosowywania z pierwszą postacią normalną, ponieważ w jednej struktury bazy danych do kilku postaci. kolumnie może się znaleźć więcej niż jedna wartość. Dostosowywanie to musi być precyzyjne Jeśli chodzi o drugi warunek, to tabela film i odbywać się w określonej kolejności. zawierająca kolumny aktor1, aktor2, aktor3 i tak Mówimy, że baza danych jest pierwszej postaci dalej, nie będzie w pierwszej postaci normalnej, normalnej (1NF), jeżeli: ponieważ powtarzające się kolumny zawierają ten sam rodzaj informacji. Każda kolumna zawiera tylko jedną wartość (czyli jest atomowa lub niepodzielna). Proces normalizacji rozpocznę od sprawdzenia, czy aktualna struktura bazy (tabela 6.2) jest zgodna Żadna tabela nie ma powtarzających się z 1NF. Kolumny, które nie są atomowe, zostaną kolumn dla danych pozostających w pewnej rozbite na wiele kolumn. Jeśli tabela posiada zależności. powtarzające się, podobne kolumny, to zostaną one przekształcone w osobną tabelę. Aby uczynić bazę zgodną z 1NF: 1. Zidentyfikuj pole, które może zawierać kilka informacji naraz. Gdy spojrzysz jeszcze raz na tabelę 6.2, zobaczysz, że jedno z pól nie jest zgodne Projekt bazy danych z 1NF: actual name. Zawiera ono zarówno imię jak i nazwisko użytkownika. Pole message date (data dodania do bazy) przechowuje, co prawda, dzień, miesiąc i rok, ale raczej nie będzie nas interesować taki poziom szczegółowości i potraktujemy Tabela 6.3. Tabela z atomowymi kolumnami przechowywaną przez nie wartość jako Baza danych forum niepodzielną. Zresztą pod koniec poprzedniego Element Przykład rozdziału pokazałem, że MySQL potrafi message ID 1 doskonale obsługiwać dane reprezentujące username janek daty i czas za pomocą typu DATETIME. password haslo Gdyby tabela zawierała na przykład jedną, first name Jan wspólną kolumnę dla imienia i nazwiska zamiast last name Kowalski dwóch osobnych albo przechowywała wiele user email jank@example.com numerów telefonów (stacjonarny, komórkowy, forum MySQL domowy, służbowy) w jednej kolumnie, message subject Pytanie na temat normalizacji to kolumny te również należałoby rozbić. message body Nie rozumiem jednej rzeczy. Dla drugiej postaci normalnej 2. Rozbij wszystkie pola odszukane w kroku 1. (2NF) podano... na kilka mniejszych, niepodzielnych pól message date 2 lutego 2008 12:20 (tabela 6.3). 179
  • 11. Rozdział 6. Aby poradzić sobie z tym problemem, utwórz Wskazówki osobne pola first name i last name, które będą Dostosowanie tabeli do 1NF wymaga zawierać tylko jedną wartość. analizy tabeli w poziomie. Wszystkie 3. Przekształć każdą grupę powtarzających się kolumny jednego rekordu przeglądamy kolumn w osobną tabelę. pod kątem występowania w nich danych, które nie są atomowe oraz występowania Problem ten nie występuje w bazie danych powtarzających się, podobnych danych. forum. Zademonstruję go zatem na przykładzie przedstawionym w tabeli 6.4. Powtarzające się Postacie normalne opisane są w różnych kolumny zawierające informacje o aktorach źródłach w różny sposób, często z użyciem powodują dwa problemy. Po pierwsze, bardziej technicznego żargonu. dla każdego filmu można podać tylko Najważniejszy jest jednak sens i końcowy ograniczoną liczbę aktorów. Nawet jeśli rezultat procesu normalizacji, a nie wprowadzimy kolumny aktor 1 aż do aktor 100, słownictwo zastosowane do jego opisu. to ograniczeniem będzie stu aktorów. Po drugie, każdy rekord, który nie zawiera maksymalnej Tabela 6.4. Tabela film nie jest zgodna z 1NF liczby aktorów, będzie mieć wartości NULL z dwóch powodów. Po pierwsze, zawiera w nadmiarowych kolumnach. W schemacie powtarzające się kolumny podobnych danych bazy danych powinniśmy unikać kolumn (aktor1 itd.). Po drugie, kolumny aktor i reżyser zawierających wartości NULL. Dodatkowym nie zawierają wartości atomowych problemem jest również to, że kolumny Tabela film zawierające informacje o reżyserze i aktorach Kolumna Wartość nie są atomowe. film ID 976 Projekt bazy danych Aby rozwiązać problemy występujące w tabeli tytuł filmu Casablanca film, utworzę dodatkową tabelę (tabela 6.5). rok produkcji 1943 Każdy jej rekord zawiera informacje o jednym reżyser Michael Curtiz autorze, co rozwiązuje problemy opisane aktor1 Humphrey Bogart powyżej. Także nazwiska i imiona aktorów są aktor2 Ingrid Bergman teraz przechowywane jako wartości atomowe. aktor3 Peter Lorre Zwróć również uwagę, że do nowej tabeli dodałem kolumnę indeksu głównego. Zasada, Tabela 6.5. Aby tabela film (tabela 6.4) była zgodna że każda tabela posiada klucz główny, wynika z 1NF, powiążę aktorów z filmami za pomocą tabeli wprost z pierwszej postaci normalnej. film-aktor 4. Upewnij się, że wszystkie nowe pola utworzone Tabela film-aktor w kroku 2. i 3. są zgodne z 1NF. ID Film Imię aktora Nazwisko aktora 1 Casablanca Humphrey Bogart 2 Casablanca Ingrid Bergman 3 Casablanca Peter Lorre 4 Sokół maltański Humphrey Bogart 5 Sokół maltański Peter Lorre 180
  • 12. Zaawansowany SQL i MySQL Druga postać normalna Każda baza, która ma spełniać drugą postać normalną (2NF), musi być najpierw zgodna z 1NF (proces normalizacji trzeba przeprowadzać we właściwej kolejności). Następnie wszystkie kolumny, które nie zawierają kluczy (kluczy obcych), muszą być powiązane zależnością z kluczem głównym. Kolumny, które naruszają ten warunek, Rysunek 6.2. Aby baza danych o filmach była zgodna łatwo zidentyfikować po tym, że zawierają wartości z 2NF, potrzebne są cztery tabele. Reżyserzy są niebędące kluczami i powtarzające się w różnych reprezentowani w tabeli film za pomocą klucza rekordach. Wartości te muszą zostać umieszczone reżyser ID; filmy są reprezentowane w tabeli film-aktor za pomocą klucza film ID; aktorzy są w osobnej tabeli i być powiązane z tabelą wyjściową reprezentowani w tabeli film-aktor za pomocą za pomocą klucza. klucza aktor ID Przykładem może być fikcyjna tabela film (tabela 6.4), która zawierałaby ponad dwadzieścia razy nazwisko Martina Scorsese jako reżysera różnych filmów. Sytuacja taka jest niezgodna z drugą postacią normalną, ponieważ kolumna zawierająca informację o reżyserze nie jest kluczem i nie jest powiązana zależnością z kluczem głównym (film ID). Rozwiązanie polega na utworzeniu osobnej tabeli reżyserzy wyposażonej we własny klucz główny, Projekt bazy danych który wystąpiłby jako klucz obcy w tabeli film, tworząc w ten sposób powiązanie obu tabel. Patrząc na tabelę 6.5, można dostrzec dwa kolejne naruszenia drugiej 2NF — ani tytuły filmów, ani nazwiska aktorów nie są powiązane z kluczem głównym tabeli. Zatem baza danych o filmach w najprostszej postaci wymaga czterech tabel (rysunek 6.2). W ten sposób informacje o każdym filmie, aktorze i reżyserze są przechowywane tylko jeden raz, a każda kolumna niebędąca kluczem jest zależna od klucza głównego danej tabeli. W zasadzie proces normalizacji można by określić jako tworzenie coraz większej liczby tabel, tak aby całkowicie wyeliminować możliwość powielenia jakichkolwiek danych. 181
  • 13. Rozdział 6. Aby uczynić bazę zgodną z 2NF: 1. Zidentyfikuj kolumny, które nie są kluczami i które nie są powiązane z kluczem głównym. Przyglądając się tabeli 6.3 zauważysz, że żadne z pól username, first name, last name, email i forum nie są kluczami (jedyną kolumną będącą kluczem jest na razie message ID) i żadne z nich nie jest powiązane zależnością z message ID. Natomiast message subject, body i date również Rysunek 6.3. Aby baza danych forum była zgodna nie są kluczami, ale ich wartości zależą od klucza z 2NF, potrzebne są trzy tabele message ID. 2. Utwórz odpowiednie tabele (patrz rysunek 6.3). Najlogiczniejsza modyfikacja istniejącej struktury polega na utworzeniu trzech tabel: users, forums i messages. Na diagramie bazy danych każda tabela została przeze mnie oznaczona prostokątem. Jej nazwa pełni rolę nagłówka, pod którym wymienione są wszystkie kolumny (atrybuty) tabeli. 3. Przypisz lub utwórz nowe klucze główne Projekt bazy danych (rysunek 6.4). Rysunek 6.4. Każda tabela powinna mieć własny Posługując się technikami opisanymi wcześniej klucz główny w tym rozdziale, upewnij się, że każda nowa tabela ma zdefiniowany klucz główny. W tabeli users stworzyłem klucz user ID, a w tabeli forums klucz forum ID. Ponieważ pole username w tabeli users oraz pole name w tabeli forums muszą być unikalne dla każdego rekordu i zawsze mieć wartość, to mógłbyś użyć ich jako kluczy głównych. Oznaczałoby to jednak, że wartości tych pól nie mogą się zmieniać (zgodnie z jednym z kryteriów wyboru klucza głównego). Użycie kluczy tekstowych zamiast numerycznych powodowałoby również nieco wolniejsze działanie bazy danych. 182
  • 14. Zaawansowany SQL i MySQL 4. Utwórz pomocnicze klucze obce, które połączą tabele zależnościami (rysunek 6.5). Ostatni krok na drodze do zgodności z 2NF polega na dodaniu kluczy obcych, które określą powiązania między tabelami. Pamiętaj, że to, co w jednej tabeli jest kluczem głównym, w drugiej najprawdopodobniej będzie kluczem obcym. W naszym przykładzie kolumna user ID z tabeli users łączy się z kolumną user ID z tabeli Rysunek 6.5. Aby zdefiniować zależność między messages. Dlatego też tabela users pozostaje tymi trzema tabelami, dodałem do tabeli messages w zależności „jeden do wielu” z tabelą messages dwa klucze obce, z których każdy łączy ją z jedną (każdy użytkownik może umieścić na forum z pozostałych dwóch tabel wiele wiadomości, ale każda wiadomość może mieć tylko jednego autora). Połączone zostały również dwie kolumny forum ID, tworząc w ten sposób zależność „jeden do wielu” pomiędzy tabelami messages i forums (każda wiadomość może należeć tylko do jednego forum, ale dane forum może zawierać wiele wiadomości). Projekt bazy danych Wskazówki Inny sposób sprawdzenia, czy tabele W prawidłowo znormalizowanej bazie danych spełniają drugą postać normalną, polega w jednej tabeli nie mają prawa pojawić się na przyjrzeniu się powiązaniom tabel. dwa takie same rekordy (dwa lub więcej Idealna sytuacja polega na występowaniu rekordów, w których wartości występujące samych zależności „jeden do wielu”. w poszczególnych kolumnach są identyczne). Tabele podlegające zależnościom „wiele Aby łatwiej przyswoić sobie proces normalizacji, do wielu” mogą wymagać restrukturyzacji. zapamiętaj, że pierwsza postać normalna Jeśli przyjrzymy się jeszcze raz rysunkowi wiąże się z analizą tabeli w poziomie, podczas 6.2, możemy zauważyć, że tabela film-aktor gdy druga postać normalna powstaje na skutek spełnia funkcję tabeli pośredniczącej. analizy w pionie (poszukiwania wartości Pozwala ona zamienić zależność „wiele powtarzających się w wielu rekordach). do wielu” zachodzącą pomiędzy filmami i aktorami na dwie zależności „jeden do wielu”. Tabele pośredniczące łatwo rozpoznać po tym, że wszystkie ich kolumny są kluczami obcymi. W tym przypadku kolumna odgrywająca rolę klucza głównego nie jest potrzebna, ponieważ kluczem głównym może być kombinacja obu kolumn tabeli. 183
  • 15. Rozdział 6. Trzecia postać normalna Aby uczynić bazę zgodną z 3NF: Mówimy, że baza danych spełnia trzecią postać 1. Zidentyfikuj wszystkie pola, które nie są normalną (3NF), jeżeli jest ona zgodna z 2NF, bezpośrednio powiązane z kluczem a każda kolumna, która nie jest kluczem, jest zależna głównym. od klucza głównego. Jeżeli prawidłowo przeszedłeś Jak już wspomniałem, na tym etapie przez pierwsze dwa etapy normalizacji, poszukujemy kolumn, które powiązane są prawdopodobnie dostosowanie bazy danych do 3NF między sobą zależnościami (tak jak miasto nie będzie już wymagać żadnych zmian. W moim i stan) zamiast z kluczem głównym. przykładzie (patrz rysunek 6.5) również nie ma W bazie danych forum nie występowały problemów, które należałoby rozwiązać, aby baza takie zależności. Przyjrzyjmy się tabeli była zgodna z trzecią postacią normalną. Dlatego messages. Każda wartość pola subject też przedstawię je omawiając hipotetyczną sytuację. jest specyficzna dla danego message ID, Weźmy na przykład pojedynczą tabelę każda wartość pola body jest specyficzna przechowującą informacje o zarejestrowanych dla wybranego message ID itd. klientach: imię, nazwisko, e-mail, numer telefonu, 2. Utwórz odpowiednie tabele. adres pocztowy itp. Tabela taka nie jest zgodna Jeśli w punkcie 1. udało się odnaleźć z 3NF, ponieważ wiele kolumn nie będzie zależnych problematyczne kolumny, takie jak od klucza głównego. Nazwa ulicy będzie zależeć na przykład miasto i stan, to tworzymy od miasta, a miasto od stanu. Również kod pocztowy dla nich osobne tabele cities i states. nie będzie zależeć od tego, jaką osobę opisuje 3. Przypisz lub utwórz nowe klucze główne. rekord. Aby znormalizować taką bazę danych, powinno się stworzyć osobną tabelę reprezentującą Każda tabela musi mieć klucz główny, wobec czego do nowych tabel dodaję Projekt bazy danych państwa, osobną reprezentującą miasta (połączoną kluczem obcym z tabelą państw) i jeszcze inną kolumny city ID i state ID. dla kodów. Wszystkie te tabele byłyby połączone 4. Utwórz pomocnicze klucze obce, definiując z tabelą opisującą klientów. tym samym zależności (rysunek 6.6). Jeśli takie rozwiązanie wydaje Ci się przesadą, Na zakończenie dodałem do tabeli Cities to masz rację. Wyższy stopień normalizacji często klucz obcy State ID oraz klucz obcy City ID nie jest konieczny. Chociaż powinno się dążyć do tabeli Clients. W efekcie uzyskałem połączenie rekordu klienta nie tylko do jak najpełniejszej normalizacji, to czasami warto z informacją o mieście, w którym jest ją poświęcić na rzecz prostoty. (patrz ramka zameldowany, ale również o stanie. „Rezygnacja z normalizacji”). W praktyce stopień normalizacji zależy od potrzeb konkretnej aplikacji i szczegółów bazy danych. Jak już wspomniałem, nasz przykład bazy forum nie wymaga dalszej normalizacji (jest już zgodny z 3NF) i dlatego proces dostosowywania do trzeciej postaci normalnej przedstawię właśnie na przykładzie omówionej wyżej bazy danych o klientach. Rysunek 6.6. Uproszczona wersja hipotetycznej bazy clients będzie zawierać dwie nowe tabele przechowujące informacje o miastach i stanach 184
  • 16. Zaawansowany SQL i MySQL Wskazówka W praktyce nie normalizowałbym tabeli Clients aż do takiego stopnia. Gdybym pozostawił pola opisujące miasto i stan w tabeli Clients, to najgorszą rzeczą, jaka mogłaby się zdarzyć, byłaby zmiana nazwy miasta i związana z tym konieczność aktualizacji rekordów wszystkich klientów będących jego mieszkańcami. W rzeczywistości jednak sytuacja taka zdarza się bardzo rzadko. Mimo istnienia zasad normalizacji baz danych dwóch różnych projektantów może dokonać normalizacji tej samej bazy w nieco inny sposób. Projektowanie baz danych pozostawia pewien margines dla indywidualnych preferencji Rezygnacja z normalizacji i interpretacji. Najważniejsze jest, Choć spełnienie trzeciej postaci normalnej by zaprojektowana baza danych nie naruszała jest korzystne, nie oznacza to jeszcze, postaci normalnej, gdyż prędzej czy później że masz normalizować każdą bazę danych, doprowadzi to do pojawienia się poważnych z którą pracujesz. Jednocześnie problemów. powinieneś uzmysłowić sobie, że odejście od sprawdzonych metod może mieć Projekt bazy danych w perspektywie dłuższego czasu katastrofalne skutki. Z normalizacji rezygnuje się zazwyczaj z dwóch powodów — ze względu na wydajność i dla wygody. Dużo łatwiej jest ogarnąć mniejszą liczbę tabel, a poza tym — łatwiej się nimi zarządza. Ze względu na liczbę powiązań między tabelami, uaktualnianie, odczytywanie i modyfikowanie danych w znormalizowanych bazach danych trwa z reguły dłużej. Krótko mówiąc, normalizacja jest poświęceniem prostoty i szybkości na rzecz spójności i skalowalności. Należy jednak pamiętać, że istnieje znacznie więcej sposobów na przyspieszenie bazy danych niż na odzyskanie informacji utraconych na skutek przechowywania ich w źle zaprojektowanej bazie. W miarę nabywania doświadczenia będziesz potrafił coraz lepiej modelować bazy danych, ale mimo wszystko staraj się trzymać po stronie normalizacji. 185
  • 17. Rozdział 6. Tworzenie bazy danych 2. Utwórz bazę danych forum (rysunek 6.7). Aby zakończyć projekt bazy danych, musimy CREATE DATABASE forum; wykonać trzy ostatnie kroki: USE forum; 1. Sprawdzić, czy w bazie znajdą się wszystkie Możliwe, że Twoja konfiguracja nie pozwala potrzebne informacje. na tworzenie nowych baz danych. W takiej sytuacji po prostu wykorzystaj jakąś już 2. Zidentyfikować typy kolumn. istniejącą bazę i dodawaj do niej kolejne 3. Nazwać wszystkie elementy bazy danych. tabele. Ostateczny projekt bazy danych został Tabela 6.6. Ostateczny projekt bazy forum przedstawiony w tabeli 6.6. W porównaniu wraz z typami kolumn do rysunku 6.5 została dodana jeszcze jedna forum kolumna. Ponieważ wiadomość umieszczana Nazwa kolumny Tabela Typ kolumny na forum może być odpowiedzią na inną wiadomość, musimy jakoś reprezentować tę zależność w bazie. forum_id forums TINYINT Rozwiązanie polega na dodaniu kolumny parent_id name forums VARCHAR(60) w tabeli messages. Jeśli wiadomość jest odpowiedzią, message_id messages INT to jej pole parent_id będzie zawierać wartość pola forum_id messages TINYINT message_id oryginalnej wiadomości (czyli message_id parent_id messages INT spełnia funkcję klucza obcego w tej samej tabeli). user_id messages MEDIUMINT Jeśli pole parent_id ma wartość równą 0, oznacza subject messages VARCHAR(100) to, że wiadomość stanowi początek nowego wątku, body messages LONGTEXT czyli nie jest odpowiedzią na żadną inną wiadomość. date_entered messages TIMESTAMP Projekt bazy danych user_id users MEDIUMINT Jeśli wprowadzasz jakiekolwiek zmiany w strukturze username users VARCHAR(30) tabel, powinieneś ponownie sprawdzić, czy spełniają pass users CHAR(40) one wszystkie postacie normalne, aby mieć pewność, first_name users VARCHAR(20) że baza danych jest nadal znormalizowana. last_name users VARCHAR(40) Zagadnienie nazw tabel i kolumn oraz wyboru typów email users VARCHAR(80) kolumn omówiłem już w rozdziale 4. Gdy schemat jest gotowy, możesz utworzyć odpowiadającą mu bazę danych MySQL-a za pomocą poleceń omówionych w rozdziale 5., „Wprowadzenie do SQL”. Aby utworzyć bazę danych: 1. Użyj wybranego klienta do dostępu do serwera Rysunek 6.7. Najpierw musisz utworzyć MySQL-a. i wybrać bazę danych Podobnie jak w poprzednim rozdziale, we wszystkich przykładach będziemy posługiwali się monitorem (klientem) mysqla. Oczywiście możesz też śmiało korzystać z phpMyAdmina i innych narzędzi. 186
  • 18. Zaawansowany SQL i MySQL 3. Utwórz tabelę forums (rysunek 6.8). Tabela ta zawiera tylko dwie kolumny CREATE TABLE forums ( (sytuacja taka ma często miejsce w przypadku forum_id TINYINT UNSIGNED znormalizowanych baz danych). Ponieważ nie NOT NULL AUTO_INCREMENT, spodziewam się, że tabela ta będzie zawierać name VARCHAR(60) NOT NULL, dużą liczbę rekordów, klucz główny otrzymał PRIMARY KEY (forum_id) ); typ TINYINT. Jeśli chcesz, by baza zawierała również opis każdego forum, możesz dodać Kolejność, w jakiej tworzysz tabele, do tej tabeli kolumnę typu VARCHAR(255). nie ma oczywiście znaczenia. Ja zacznę od forums. Pamiętaj, że zawsze możesz 4. Utwórz tabelę messages (rysunek 6.9). rozpisać polecenie SQL w kilku wierszach CREATE TABLE messages ( na ekranie, jeżeli tylko będzie Ci tak message_id INT UNSIGNED NOT NULL AUTO_INCREMENT, wygodniej. forum_id TINYINT UNSIGNED NOT NULL, parent_id INT UNSIGNED NOT NULL, user_id MEDIUMINT UNSIGNED NOT NULL, subject VARCHAR(100) NOT NULL, body LONGTEXT NOT NULL, date_entered TIMESTAMP NOT NULL, PRIMARY KEY (message_id) ); W tym przypadku klucz główny musi być zdecydowanie bardziej pojemny, ponieważ Projekt bazy danych spodziewam się, że tabela ta będzie zawierać bardzo dużo rekordów. Trzy kolumny będące kluczami obcymi — forum_id, parent_id i user_id — będą mieć taki sam rozmiar i typ Rysunek 6.8. Utwórz pierwszą tabelę jak ich odpowiedniki będące kluczami głównymi w innych tabelach. Pole subject zostało ograniczone do 100 znaków, a pole body może zawierać znaczną ilość tekstu. Pole date_entered otrzymało typ TIMESTAMP. Będzie ono przechowywać datę i czas dodania rekordu. Jego wartość zostanie automatycznie zaktualizowana (bieżącą datą i czasem) w momencie wstawienia rekordu (właśnie w ten sposób zachowuje się typ TIMESTAMP). Rysunek 6.9. Utwórz drugą tabelę 187
  • 19. Rozdział 6. 5. Utwórz tabelę users (rysunek 6.10). 6. Jeśli chcesz, możesz upewnić się, że baza CREATE TABLE users ( danych ma taką strukturę jak powinna user_id MEDIUMINT UNSIGNED (rysunek 6.11). NOT NULL AUTO_INCREMENT, SHOW TABLES; username VARCHAR(30) NOT NULL, SHOW COLUMNS FROM forums; pass CHAR(40) NOT NULL, SHOW COLUMNS FROM messages; first_name VARCHAR(20) NOT NULL, SHOW COLUMNS FROM users; last_name VARCHAR(40) NOT NULL, email VARCHAR(80) NOT NULL, Ten krok jest opcjonalny, ponieważ MySQL PRIMARY KEY (user_id) ); i tak wyświetla informacje o pomyślnym wykonaniu każdego wprowadzanego Większość kolumn tej tabeli wykorzystuje polecenia. Warto jednak przypomnieć definicje znane z tabeli users bazy sitename sobie strukturę bazy danych. używanej w poprzednich dwóch rozdziałach. Kolumna pass jest typu CHAR(40), ponieważ Wskazówka dla haseł będę stosować funkcję SHA1(), która W przypadku połączenia klucz zwraca zawsze łańcuch o długości 40 znaków główny-klucz obcy (na przykład forum_id (patrz rozdział 5.). tabeli forum z forum_id tabeli messages), obie kolumny muszą być tego samego typu (w naszym przykładzie: TINYINT UNSIGNED NOT NULL). Projekt bazy danych Rysunek 6.10. Trzecia i ostatnia tabela w bazie Rysunek 6.11. Sprawdź strukturę bazy za pomocą polecenia SHOW 188
  • 20. Zaawansowany SQL i MySQL Wypełnianie bazy danych Aby zapełnić bazę danymi: W rozdziale 15. napiszemy w PHP interfejs 1. Dodaj kilka nowych rekordów do tabeli forums WWW dla bazy forums. Będzie on dostarczać (rysunek 6.12). standardowego sposobu wypełniania bazy INSERT INTO forums (name) VALUES ('MySQL'), danymi (poprzez rejestrowanie się ('PHP'), ('Programowanie'), ('HTML'), użytkowników i umieszczanie wiadomości ('CSS'), ('Bazy danych'); na forum). Zanim jednak dojdziemy do tego Ponieważ tablica messages jest zależna od punktu, musisz się jeszcze sporo nauczyć. wartości odczytywanych z tabel forums i users, Dlatego na razie wypełnimy bazę danymi wypełnię najpierw te ostatnie. W przypadku za pomocą klienta mysqla. Możesz wykonać powyższego polecenia INSERT wystarczy jedynie po kolei poniższe kroki lub skorzystać podać wartość kolumny name (MySQL z gotowych poleceń SQL-a dołączonych do automatycznie nada wartość kolumnie forum_id). przykładów zamieszczonych na serwerze ftp. 2. Dodaj nowe rekordy do tabeli users (rysunek 6.13). INSERT INTO users (username, pass, first_name, last_name, email) VALUES ('janek', SHA1('haslo'), 'Jan', 'Kowalski', 'jank@example.com'), ('ak', SHA1('haselko'), 'Arkadiusz', 'Kaczmarek', 'ak@example.com'), ('GosiaM', SHA1('tajne'), 'Małgorzata', 'Malinowska', 'mm@example.com'); Rysunek 6.12. Dodawanie rekordów do tabeli forums Projekt bazy danych Jeśli masz wątpliwości co do składni polecenia INSERT lub zastosowania funkcji SHA1(), skorzystaj z informacji podanych w rozdziale 5. Rysunek 6.13. Dodawanie rekordów do tabeli users 189
  • 21. Rozdział 6. 3. Wstaw nowe rekordy do tabeli messages Sprawę dodatkowo komplikuje kolumna (patrz rysunek 6.14). parent_id. Musi ona zawierać wartość SELECT * FROM forums; message_id tej wiadomości, na którą SELECT user_id, username FROM users; odpowiedź stanowi nowa wiadomość. INSERT INTO messages (forum_id, Druga wiadomość umieszczona w bazie parent_id, user_id, subject, body) danych będzie mieć message_id równy VALUES (1, 0, 1, 'Pytanie na temat normalizacji', 2 i wobec tego każda wiadomość stanowiąca 'Nie rozumiem jednej rzeczy. Dla drugiej odpowiedź na tę wiadomość będzie musiała postaci normalnej (2NF) podano...'), mieć wartość parent_id równą 2. (1, 0, 2, 'Projekt bazy danych', 'Projektuję nową bazę danych i natrafiłem na pewien W tworzonych przez Ciebie skryptach problem. Ile tabel powinna mieć moja PHP, wszystko to będzie wyglądało baza?...'), (1, 2, 1, 'Projekt bazy danych', 'Liczba znacznie prościej. Muszę teraz jednak tabel w Twojej bazie danych...'), wyłożyć Ci całą teorię, posługując się (1, 3, 2, 'Projekt bazy danych', 'OK, terminologią języka SQL. dziękuję!'), (2, 0, 3, 'Błędy PHP', 'Próbuję uruchomić Zwróć również uwagę, że nie wprowadziłem skrypty z rozdziału 3. i pierwszy skrypt wartości dla pola date_entered. MySQL kalkulatora nie działa. Gdy akceptuję automatycznie umieści w nim bieżącą formularz...'); datę i czas, ponieważ jest to kolumna Ponieważ dwa pola tabeli messages (forum_id typu TIMESTAMP. oraz user _id) odwołują się do wartości 4. Powtórz kroki od 1. do 3., aby zapełnić przechowywanych w innych tabelach, bazę danymi. przed wstawieniem nowych rekordów Projekt bazy danych dokonam wyboru tych wartości. Na przykład, We wszystkich kolejnych przykładach gdy użytkownik janek utworzy nową wiadomość w tym rozdziale będę wykorzystywał bazę, na forum MySQL-a, musisz użyć forum_id którą właśnie zapełniłem. Jeśli chcesz, równy 1 i user_id równy 1. możesz wykonać u siebie te same polecenia INSERT co ja lub utworzyć swoje własne. Rysunek 6.14. W przypadku znormalizowanych baz danych bardzo często spotkasz się z sytuacją, w której, aby wstawić jakiś rekord do tabeli, będziesz musiał znać wartości przechowywane w innych tabelach 190
  • 22. Zaawansowany SQL i MySQL SELECT * FROM messages Złączenia INNER JOIN forums ON messages.forum_id = Ponieważ relacyjne bazy danych mają złożoną forums.forum_id strukturę, aby wydobyć te informacje, które WHERE forums.name = 'MySQL' najbardziej nas interesują, musimy czasem Złączenie to wybiera wszystkie kolumny obu tabel, wykonać jakieś niestandardowe zapytanie. jeśli spełnione są dwa warunki. Po pierwsze, Na przykład, jeśli chcesz dowiedzieć się, jakie kolumna forums.name musi zawierać wartość wiadomości zawiera forum MySQL-a, musisz najpierw dowiedzieć się, jaka jest wartość MySQL (której odpowiada wartość forum_id forum_id dla tego forum, a następnie użyć równa 1). Po drugie, wartość forum_id w tabeli forums musi odpowiadać wartości forum_id jej do pobrania wszystkich rekordów tabeli message, które mają taką wartość forum_id. w tabeli messages. Ze względu na sprawdzenie Jak z tego wynika, to proste zadanie wymaga równości dotyczące pól w różnych tabelach wykonania dwóch zapytań. Jednak stosując (messages.forum_id = forums.forum_id) złączenie złączenie, możesz poradzić sobie z nim takie nazywa się równościowym. w jednym kroku. Złączenia wewnętrzne możesz również zapisywać Złączenie jest zapytaniem SQL-a używającym bez stosowania klauzuli INNER JOIN: dwóch lub więcej tabel i tworzącym wirtualną SELECT * FROM messages, forums WHERE tabelę wyników. W specyfikacji SQL-a messages.forum_id = forums.forum_id AND forums.name = 'mySQL' występują dwa główne typy złączeń: wewnętrzne i zewnętrzne (oba mają szereg Jeżeli wybierasz dane z wielu tabel i kolumn, podtypów). a w kilku tabelach występują kolumny o takiej samej nazwie, musisz zastosować notację z kropką Złączenie wewnętrzne zwraca wszystkie (tabela.kolumna). W przypadku relacyjnych baz rekordy podanych tabel, dla których zachodzi danych robi się to praktycznie zawsze, ponieważ dopasowanie. Na przykład, aby uzyskać Złączenia klucz główny jednej tabeli ma taką samą nazwę wszystkie wiadomości zamieszczone jak obcy klucz drugiej. Jeżeli nie wskażesz na forum MySQL, powinieneś użyć jednoznacznie kolumny, do której się odwołujesz, następującego złączenia wewnętrznego zobaczysz komunikat o błędzie (rysunek 6.16). (rysunek 6.15): Rysunek 6.15. To złączenie zwraca kolumny obu tabel dla rekordów, dla których wartości forum_id są równe MySQL (1) Rysunek 6.16. Ogólne odwołanie do kolumny występującej w kilku tabelach spowoduje wystąpienie błędu niejednoznaczności 191
  • 23. Rozdział 6. Złączenia zewnętrzne różnią się od złączeń Jeżeli w warunku porównania złączenia wewnętrznych tym, że potrafią zwracać rekordy, zewnętrznego bądź wewnętrznego występuje które nie spełniają wyrażenia warunkowego. kolumna o takiej samej nazwie w obu tabelach, Istnieją trzy podtypy złączeń zewnętrznych: left możesz uprościć zapis zapytania, stosując (lewe), right (prawe) i full (pełne). Przykładem klauzulę USING: pierwszego podtypu jest następujące złączenie: SELECT * FROM messages SELECT * FROM forums INNER JOIN forums LEFT JOIN messages ON USING (forum_id) forums.forum_id = messages.forum_id; WHERE forums.name = 'mySQL' SELECT * FROM forums Najważniejsze przy tego rodzaju złączeniach LEFT JOIN messages jest to, które tabele należy wymienić jako pierwsze. USING (forum_id) W powyższym przykładzie w przypadku udanego Zanim przejdę do przykładów, jeszcze dwie dopasowania zwrócone zostaną wszystkie rekordy uwagi. Po pierwsze, ponieważ składnia tabeli forums wraz ze wszystkimi informacjami wymagana przy tworzeniu złączeń jest dość z tabeli messages. Jeśli dla danego rekordu tabeli skomplikowana, przy ich pisaniu przydają się forums nie można dopasować informacji w tabeli aliasy omówione w rozdziale 5. Po drugie, messages, to zamiast nich zostaną zwrócone ponieważ złączenia często zwracają dużo wartości NULL (rysunek 6.17). danych, to najlepiej zawsze określić, które kolumny nas interesują, zamiast wybierać wszystkie. Złączenia Rysunek 6.17. To złączenie zewnętrzne zwraca więcej rekordów niż złączenie wewnętrzne, ponieważ zwraca wszystkie wiersze pierwszej tabeli. Zapytanie to zwraca również nazwy wszystkich forów, nawet jeśli nie zawierają one jeszcze żadnej wiadomości 192
  • 24. Zaawansowany SQL i MySQL Aby wykorzystać złączenia: 2. Pobierz temat i datę wprowadzenia każdej wiadomości wysłanej przez użytkownika janek 1. Pobierz nazwę forum i temat wiadomości (rysunek 6.19). dla każdego rekordu tabeli messages (patrz rysunek 6.18). SELECT m.subject, DATE_FORMAT(m.date_entered, SELECT f.name, m.subject '%M %D, %Y') AS Date FROM forums FROM users AS u INNER JOIN AS f INNER JOIN messages AS m messages AS m USING (forum_id) ORDER BY f.name; USING (user_id) WHERE u.username = 'janek'; Zapytanie to zawiera złączenie wewnętrzne, które spowoduje w efekcie zastąpienie Również to złączenie używa dwóch tabel, wartości forum_id z tabeli messages users i messages. Złączenie obu tabel odbywa odpowiadającą jej wartością name z tabeli się za pomocą kolumny user_id i dlatego forums dla każdego rekordu tabeli messages. została ona umieszczona wewnątrz klauzuli W wyniku otrzymasz zatem temat każdej USING. Wyrażenie warunkowe WHERE pozwala wiadomości wraz z nazwą forum, do którego zidentyfikować interesującego nas użytkownika, należy ta wiadomość. a funkcja DATE_FORMAT sformatować wartość pola date_entered. Zwróć uwagę, że w połączeniach nadal możesz używać klauzul ORDER BY. Złączenia Rysunek 6.18. Podstawowe złączenie wewnętrzne Rysunek 6.19. Nieco bardziej skomplikowana wersja zwraca w tym przykładzie tylko dwie kolumny złączenia wewnętrznego tabele users i messages 193
  • 25. Rozdział 6. 3. Pobierz identyfikator wiadomości, temat oraz 4. Dla każdego użytkownika pobierz nazwę nazwę forum dla każdej wiadomości, której użytkownika, temat wiadomości i nazwę autorem jest użytkownik janek (patrz forum (patrz rysunek 6.21). rysunek 6.20). SELECT u.username, m.subject, SELECT m.message_id, m.subject, f.name FROM users AS u LEFT JOIN f.name FROM users AS u messages AS m USING (user_id) INNER JOIN LEFT JOIN forums AS f messages AS m USING (user_id) USING (forum_id); INNER JOIN forums AS f USING (forum_id) Gdybyś zastosował podobne złączenie WHERE u.username = 'janek'; wewnętrzne, to użytkownicy, którzy nie są jeszcze autorami żadnej wiadomości, Powyższe złączenie jest podobne nie zostaliby uwzględnieni (patrz rysunek do zastosowanego w punkcie 2., ale idzie o krok 6.22). Zatem jeśli interesują Cię wszyscy dalej, dołączając trzecią tabelę. Zwróć szczególną użytkownicy, powinieneś użyć złączenia uwagę na sposób konstrukcji złączenia zewnętrznego. Zwróć uwagę, że tabela, wewnętrznego trzech tabel oraz zastosowanie która ma być uwzględniona w całości aliasów w celu łatwiejszego odwoływania się (users w tym przypadku), musi być podana do tabel i ich kolumn. jako pierwsza tabela złączenia typu left. Złączenia Rysunek 6.20. Złączenie wewnętrzne wszystkich trzech Rysunek 6.21. To złączenie zewnętrzne zwraca tabel bazy dla każdego użytkownika temat każdej wiadomości i nazwę każdego forum. Jeśli użytkownik nie umieścił jeszcze żadnej wiadomości na forum (tak jak tomekj widoczny na dole rysunku), to temat wiadomości i nazwa forum będą mieć dla niego wartości NULL 194
  • 26. Zaawansowany SQL i MySQL Wskazówki Złączenia, które nie zawierają klauzuli WHERE (np. SELECT * FROM urls, url_associations), Możesz nawet złączyć tabelę z nią samą. nazywamy złączeniami pełnymi. Zwracają one Złączenia można tworzyć z wykorzystaniem rekordy z obu tabel. W przypadku dużych tabel wyrażeń warunkowych odwołujących się ilość zwracanych danych może stanowić pewien do dowolnych kolumn. Nie muszą one problem. pełnić roli kluczy, choć sytuacja taka jest Nigdy nie zostanie zwrócona wartość NULL najczęstsza. występująca w kolumnie, do której odwołujemy Stosując składnię bazadanych.tabela. się w złączeniu. To dlatego, że nie jest ona równa kolumna, możesz wykonywać złączenia żadnej innej wartości, w tym także innym tabeli należących do różnych baz danych, wartościom NULL. o ile tylko wszystkie znajdują się na tym samym serwerze. Ta metoda nie zadziała, jeżeli bazy komunikują się ze sobą za pośrednictwem sieci. Złączenia Rysunek 6.22. To złączenie wewnętrzne nie zwróci użytkownika, który nie umieścił jeszcze żadnej wiadomości na forum (tak jak tomekj widoczny na dole rysunku 6.21) 195
  • 27. Rozdział 6. Grupowanie wyników zapytania Aby zgrupować dane: W poprzednim rozdziale przedstawiłem dwie 1. Policz zarejestrowanych użytkowników różne klauzule — ORDER BY i LIMIT — mające wpływ (patrz rysunek 6.23). na wynik zapytania. Pierwsza z nich umożliwia SELECT COUNT(user_id) FROM users; określenie uporządkowania zwracanych rekordów, COUNT() jest prawdopodobnie a druga pozwala określić, które z rekordów będących najpopularniejszą z funkcji agregujących. wynikiem zapytania zostaną w rzeczywistości Z jej pomocą możesz szybko zliczyć zwrócone. Kolejna klauzula, GROUP BY, grupuje rekordy tak jak w przypadku tabeli users. zwracane dane w podobne do siebie bloki informacji. Zwróć uwagę, że nie wszystkie zapytania Na przykład, aby pogrupować wszystkie wiadomości stosujące funkcje agregujące używają według forum, wpisz: klauzuli GROUP BY. SELECT * FROM messages GROUP BY forum_id; 2. Policz, ile razy każdy użytkownik umieścił na forum swoją wiadomość (patrz Zwracane dane nie będą miały postaci pojedynczych rysunek 6.24). rekordów, tylko grup informacji. Zamiast dużej liczby wiadomości pochodzących z danego forum SELECT username, COUNT(message_id) AS Number zobaczysz je wszystkie w postaci jednego rekordu. FROM users LEFT JOIN messages AS m Ten przykład nie jest być może szczególnie USING (user_id) GROUP BY (m.user_id); przydatny, ale wystarczający do przedstawienia samej koncepcji. Grupowanie wyników zapytania Z klauzulą GROUP BY często używa się jednej z funkcji Tabela 6.7. Funkcje grupujące MySQL-a agregujących przedstawionych w tabeli 6.7 (funkcji tych można używać również niezależnie od klauzuli Funkcja Przeznaczenie GROUP BY). AVG() Zwraca średnią wartość z podanej kolumny. Na wyrażenie GROUP BY możesz oczywiście nakładać MIN() Zwraca najmniejszą wartość warunki WHERE, ORDER BY i LIMIT, tworząc zapytania z podanej kolumny. w rodzaju: MAX() Zwraca największą wartość z podanej kolumny. SELECT kolumny FROM tabela WHERE warunek SUM() Zwraca sumę wszystkich wartości GROUP BY kolumna ORDER BY kolumna z danej kolumny. LIMIT x, y; COUNT() Zwraca liczbę rzędów. GROUP_CONCAT() Zwraca konkatenację wartości kolumny. Rysunek 6.23. To zapytanie grupujące zwraca liczbę wartości user_id w tabeli users 196
  • 28. Zaawansowany SQL i MySQL Jest to rozszerzona wersja zapytania W zapytaniach z klauzulą GROUP BY nadal możesz występującego w kroku 1., ale zamiast sortować wyniki zapytań. Proces ten możesz zliczać samych użytkowników, podaje uprościć, stosując alias Number dla wartości liczbę wiadomości związanych z każdym COUNT(message_id). użytkownikiem. Zastosowanie złączenia umożliwia dostęp do informacji w dwóch Wskazówki tabelach. Aby uwzględnić użytkowników, Jak już miałeś okazję się przekonać, NULL którzy nie byli jeszcze aktywni na forum, jest bardzo specyficzną wartością. Interesujące zastosowałem złączenie wewnętrzne. jest to, że wyrażenie GROUP BY umieszcza 3. Znajdź dwóch najaktywniejszych wszystkie wartości NULL w tej samej grupie, użytkowników forum (rysunek 6.25). ponieważ wszystkie one wykazują taki sam „brak wartości”. SELECT username, COUNT(message_id) AS Number Funkcja COUNT() zlicza jedynie wystąpienia FROM users wartości różnych od NULL. Dlatego pamiętaj, LEFT JOIN messages AS m USING (user_id) aby użyć jej dla każdej kolumny (*) lub GROUP BY (m.user_id) dla kolumn, które nie zawierają wartości NULL ORDER BY Number DESC LIMIT 2; (na przykład klucza głównego). Jeśli zapytanie użyte w punkcie 2. (rysunek 6.24) stosowałoby funkcję COUNT() dla wszystkich kolumn (*) zamiast tylko dla message_id, to pokazałoby Grupowanie wyników zapytania błędną wartość równą 1 dla wszystkich użytkowników, którzy nie napisali jeszcze żadnej wiadomości. Stałoby się tak, ponieważ zapytanie zwróciłoby dokładnie jeden rekord dla każdego z tych użytkowników. Opanowanie klauzuli GROUP BY i funkcji omówionych w tym podrozdziale zajmie Ci trochę czasu. Za każdym razem, gdy użyjesz Rysunek 6.24. To zapytanie GROUP BY podaje liczbę wiadomości umieszczonych na forum przez każdego nieprawidłowej składni, zostanie zgłoszony użytkownika błąd. Poeksperymentuj trochę z monitorem mysqla, aby zapamiętać, jak dokładnie muszą być sformułowane wszystkie zapytania, których będziesz chciał używać w swoich aplikacjach. Z klauzulą GROUP BY związana jest klauzula HAVING, która zachowuje się jak klauzula WHERE zastosowana do grupy rekordów. Rysunek 6.25. Klauzula ORDER BY pozwala posortować autorów na podstawie liczby wiadomości umieszczonych na forum. Klauzula LIMIT powoduje, że podane zostaną tylko dwa wyniki 197
  • 29. Rozdział 6. Indeksy Wyposażony w te wiadomości zmodyfikuję bazę forum, dodając do niej indeksy. Mechanizm indeksów to specjalny system W tabeli 6.8 podałem indeksy utworzone wykorzystywany w bazach danych do poprawy dla poszczególnych kolumn za pomocą ich wydajności. Zakładając na swych tabelach polecenia ALTER omówionego w ramce. indeksy, sprawiasz, że MySQL przywiązuje wagę do określonych kolumn. Aby indeksy mogły być wykorzystywane w sposób maksymalnie efektywny, MySQL przechowuje je w osobnych plikach. Na każdej tabeli można założyć co najmniej 16 indeksów, a każdy indeks może obejmować do 15 kolumn. Choć rozciąganie indeksu na kilka kolumn może wydawać się zastanawiające, przydaje się to podczas częstego przeszukiwania tego samego zestawu kolumn (np. imion i nazwisk, miast i województw). Nie powinieneś jednak przesadzać z indeksowaniem. Choć przyspiesza ono odczytywanie informacji z bazy, to jednocześnie spowalnia ich modyfikowanie (ponieważ informacje o zmianach muszą trafić do indeksów). Najlepszym wyjściem jest zakładanie indeksów na kolumnach, które: Często wymieniane są w zapytaniach po klauzulach WHERE. Tabela 6.8. Indeksy używane przez bazę danych Indeksy Często wymieniane są w zapytaniach forum. Nie wszystkie kolumny są indeksowane, po klauzulach ORDER BY. a dwa indeksy zostały utworzone dla par kolumn: user.pass i user.username oraz messages.body Często wykorzystywane są jako główny punkt i messages.subject złączenia. Indeksy bazy danych forum Mają wiele różnych wartości (nie powinno się Nazwa kolumny Tabela Typ indeksu indeksować kolumn zawierających wiele forum_id forums PRIMARY powtarzających się wartości). name forums UNIQUE W MySQL-u występują cztery rodzaje indeksów: message_id messages PRIMARY INDEX (standardowy), UNIQUE (który wymaga, forum_id messages INDEX aby w każdym rzędzie występowały inne wartości), parent_id messages INDEX FULLTEXT (do wyszukiwań FULLTEXT) oraz PRIMARY KEY user_id messages INDEX (klucz główny, będący szczególnym przypadkiem body/subject messages FULLTEXT indeksu UNIQUE). Pamiętaj, że dana kolumna może date_entered messages INDEX być tylko raz zaindeksowana i wobec tego wybierz user_id users PRIMARY dla niej najodpowiedniejszy rodzaj indeksu. username users UNIQUE pass/username users INDEX email users UNIQUE 198
  • 30. Zaawansowany SQL i MySQL Aby dodać indeks do istniejącej tabeli: 1. Załóż indeks na kolumnie name w tabeli forums (patrz rysunek 6.26). ALTER TABLE forums ADD UNIQUE (name); Rysunek 6.26. Dla kolumny name dodano nowy Tabela forums ma już założony indeks typu klucz indeks, który poprawi efektywność zapytań główny na kolumnie forum_id. Ponieważ name i zapobiegnie wprowadzaniu powtarzających się również jest polem, do którego będą częste wartości odwołania i którego wartość musi być unikatowa w każdym rekordzie, zakładam na nim indeks UNIQUE. Modyfikowanie tabel Polecenie ALTER służy przede wszystkim do modyfikowania struktury tabeli w bazie danych. Najczęściej oznacza to dodawanie, usuwanie bądź modyfikację kolumn, ale również dodawanie indeksów. Polecenia ALTER można również użyć do zmiany nazwy tabeli. Teoretycznie przy dobrym Indeksy projekcie bazy jej struktura nie powinna stwarzać żadnych problemów. Jednak w praktyce często zdarza się wprowadzać w niej pewne zmiany. Składnia polecenia ALTER jest następująca: ALTER TABLE nazwa_tabeli KLAUZULA; Ponieważ klauzul, które można zastosować, jest bardzo wiele, w tabeli 6.9 wymieniłem tylko najczęściej stosowane. Pełną listę znajdziesz w podręczniku MySQL-a. Tabela 6.9. Popularne warianty polecenia ALTER (gdzie t reprezentuje nazwę tabeli, c nazwę kolumny, a i nazwę indeksu. Pełną specyfikację polecenia znajdziesz w dokumentacji MySQL-a Klauzule, które można stosować w poleceniach ALTER TABLE Klauzula Sposób użycia Znaczenie ADD COLUMN ALTER TABLE t ADD COLUMN c TYP Dodaje nową kolumnę na końcu tabeli. CHANGE COLUMN ALTER TABLE t CHANGE COLUMN c c TYP Pozwala zmienić typ danych i właściwości kolumny. DROP COLUMN ALTER TABLE t DROP COLUMN c Usuwa kolumnę z tabeli razem z wszystkimi jej danymi. ADD INDEX ALTER TABLE t ADD INDEX i (c) Zakłada nowy indeks na kolumnie c. DROP INDEX ALTER TABLE t DROP INDEX i Usuwa istniejący indeks. RENAME AS ALTER TABLE t RENAME AS nowa_t Zmienia nazwę tabeli. 199
  • 31. Rozdział 6. 2. Załóż indeksy dla tabeli messages Jesli podczas wykonywania tego zapytania (patrz rysunek 6.27). pojawi się komunikat o błędzie ALTER TABLE messages stwierdzający, że typ tabeli nie obsługuje ADD INDEX(forum_id), indeksów FULLTEXT (patrz rysunek 6.28), ADD INDEX(parent_id), na razie opuść ten wiersz zapytania ADD INDEX(user_id), i sprawdź w następnym podrozdziale, ADD FULLTEXT(body, subject), ADD INDEX(date_entered); w jaki sposób zmienić typ tabeli. Ta tabela będzie mieć najwięcej indeksów, ponieważ jest najważniejszą tabelą w bazie i zawiera trzy klucze obce (forum_id, parent_id i user_id), dla których należy założyć osobne indeksy. Dodatkowo pola body i subject otrzymują indeks FULLTEXT używany podczas wyszukiwań typu FULLTEXT w dalszej części tego rozdziału. Również kolumna date_entered Rysunek 6.27. Do tabeli messages dodano kilka otrzymuje indeks, ponieważ będzie używana indeksów naraz. MySQL raportuje wykonanie przez klauzule ORDER BY (do sortowania operacji oraz podaje liczbę rekordów, których wiadomości po dacie). dotyczyła (powinna to być liczba wszystkich rekordów tabeli) Indeksy Rysunek 6.28. Indeksów FULLTEXT nie można stosować dla wszystkich typów tabel. Jeśli napotkasz ten komunikat o błędzie, to rozwiązanie znajdziesz w tym rozdziale w części „Stosowanie różnych typów tabel” 200
  • 32. Zaawansowany SQL i MySQL 3. Dodaj indeksy do tabeli users Indeks założony na kolumnach pass i username (patrz rysunek 6.29). ma za zadanie poprawić efektywność zapytań ALTER TABLE users wykonywanych podczas uwierzytelniania ADD UNIQUE (username), użytkownika, gdy kombinacja tych dwóch ADD INDEX (pass, username), kolumn będzie używana w wyrażeniu ADD UNIQUE (email); warunkowym WHERE. Tabela users będzie mieć dwa indeksy 4. Obejrzyj bieżącą strukturę wszystkich tabel UNIQUE oraz jeden indeks założony na dwóch (patrz rysunek 6.30). kolumnach. Indeksy UNIQUE zastosowałem DESCRIBE forums; w tym przypadku, ponieważ chcę zapobiec DESCRIBE messages; możliwości zarejestrowania dwóch DESCRIBE users; użytkowników o tej samej nazwie lub wielokrotnego zarejestrowania Polecenie DESCRIBE języka SQL zwraca użytkownika o tym samym adresie e-mail. informacje o nazwach kolumn występujących w tabeli i w ich typach, a także o kolejności, w jakiej one występują i o pozakładanych indeksach. Podaje ono także, czy dane pole może przyjmować wartość NULL, czy określono dla niego jakąś wartość domyślną itd. Rysunek 6.29. Indeksy zostały również dodane do trzeciej tabeli Indeksy Rysunek 6.30. Aby zobaczyć szczegółowe informacje na temat struktury tabeli, użyj polecenia DESCRIBE. Kolumna Key informuje o indeksach 201
  • 33. Rozdział 6. Wskazówki Próba założenia indeksu UNIQUE na kolumnie zawierającej duplikaty spowoduje błąd, a indeks nie zostanie utworzony. Tworząc indeks, możesz nadać mu nazwę. ALTER TABLE tabela ADD INDEX nazwa_indeksu (kolumna); Jeżeli tego nie zrobisz, otrzyma on nazwę kolumny, na której go zakładasz. Słowo COLUMN w większości poleceń ALTER jest opcjonalne. Załóżmy, że stworzyłeś indeks dla kilku kolumn: ALTER TABLE tabela ADD INDEX (kol1, kol2, kol3) Powstały indeks umożliwia efektywne przeszukiwanie kolumny kol1, kombinacji kolumn kol1 i kol2 oraz kombinacji wszystkich trzech podanych kolumn. Nie zwiększa efektywności przeszukiwania kolumny kol2 i kol3 lub ich kombinacji. Indeksy 202
  • 34. Zaawansowany SQL i MySQL Stosowanie Aby określić, którego silnika chcemy używać, na końcu polecenia CREATE dodajemy specjalną różnych typów tabeli klauzulę: MySQL obsługuje kilka różnych typów tabeli CREATE TABLE tabela ( (typ tabeli nazywany bywa również silnikiem kolumna1 TYPKOLUMNY, kolumna2 TYPKOLUMNY... przechowywania). Każdy z tych typów ma inne ) ENGINE = INNODB właściwości, odrębne ograniczenia (dotyczące ilości przechowywanych danych) Jeśli tworząc tabele, nie podamy ich typu, to MySQL i charakteryzuje się inną efektywnością użyje typu domyślnego. działania w określonych sytuacjach. Jednak Typ istniejącej tabeli możemy zmienić za pomocą interakcje użytkownika (w sensie wykonywania polecenia ALTER: zapytań) z różnymi typami tabel są spójne. ALTER TABLE tabela ENGINE = MYISAM Najważniejszym typem tabeli jest MyISAM. Jest on domyślnym typem tabeli na wszystkich Ponieważ następny przykład w tym rozdziale będzie platformach oprócz Windows. Tabele tego wymagać tabeli typu MyISAM, to pokażę najpierw typu są najodpowiedniejsze dla większości kroki konieczne do skonfigurowania odpowiedniego aplikacji i umożliwiają szybkie wykonywanie typu tabeli na przykładzie tabeli messages. W kilku poleceń SELECT oraz INSERT. Ich podstawową pierwszych krokach dowiesz się, jak sprawdzić wadą jest to, że nie obsługują transakcji. wykorzystywany typ silnika, (ponieważ zmiana typu tabeli może nie być konieczna). Stosowanie różnych typów tabeli Kolejnym typem tabeli pod względem popularności zastosowań jest InnoDB, który jest domyślnym typem tabeli MySQL-a w systemie Windows. Tabele InnoDB obsługują transakcje i umożliwiają szybkie wykonywanie poleceń UPDATE. Jednak silnik InnoDB jest w ogólnym przypadku wolniejszy niż MyISAM i wymaga większej przestrzeni dyskowej serwera. Tabele typu InnoDB nie obsługują również indeksów typu FULLTEXT (i dlatego mogłeś napotkać błąd przedstawiony na rysunku 6.28, jeśli używasz Windows). 203
  • 35. Rozdział 6. Aby zmienić typ tabeli: 2. Jeśli to konieczne, zmień typ tabeli messages na MyISAM (rysunek 6.32). 1. Obejrzyj aktualną informację o tabeli (patrz rysunek 6.31). ALTER TABLE messages ENGINE=MYISAM; SHOW TABLE STATUS; Jeśli w punkcie 1. okazało się, że typ tabeli jest inny niż MyISAM, to zmień go Polecenie SHOW TABLE STATUS zwraca wiele za pomocą powyższego polecenia przydatnych informacji o tabelach bazy danych. (nie musisz zwracać uwagi na małe i duże Informacje te odczytuje się niewygodnie, litery w typie tabeli). Jeśli wykonałeś ponieważ mają one postać szerokiej tabeli domyślną instalację i konfigurację zajmującej wiele wierszy. W każdym wierszu MySQL-a, to zmiana typu tabeli nie znajduje się najpierw nazwa tabeli, a następnie będzie potrzebna w systemie Mac OS X, jej typ. Zwykle jest nim MyISAM lub InnoDB. ale musisz jej dokonać w systemie Windows. Stosowanie różnych typów tabeli Rysunek 6.31. Zanim zmienisz typ tabeli, sprawdź go za pomocą polecenia SHOW TABLE STATUS Rysunek 6.32. Zmieniłem typ tabeli (lub silnik przechowywania) za pomocą polecenia ALTER 204
  • 36. Zaawansowany SQL i MySQL 3. Możesz sprawdzić zmianę typu tabeli, wykonując ponownie polecenie SHOW TABLE STATUS. Wskazówki Aby ułatwić odczytanie wyników dowolnego zapytania, możesz dodać w kliencie mysqla parametr G na końcu zapytania (rysunek 6.33): SHOW TABLE STATUS G Znacznik ten informuje, że tabela wyników Rysunek 6.33. Aby uzyskać bardziej czytelną powinna zostać wyświetlona pionowo zamiast postać wyników zapytania, użyłem znacznika G poziomo. Zwróć uwagę, że nie musisz w tym przypadku użyć średnika kończącego polecenie SQL, ponieważ funkcję tę spełnia znacznik G. W tej samej bazie danych mogą występować różne typy tabel. W zależności od domyślnego typu tabel w Twojej instalacji MySQL-a, stwierdzenie to może już być prawdziwe dla bazy danych forum. To samo możesz zaobserwować w przypadku bazy danych ecommerce, w której Stosowanie różnych typów tabeli tabele klientów i produktów są typu MyISAM, ale tabela zamówień jest typu InnoDB (aby umożliwić stosowanie transakcji). 205
  • 37. Rozdział 6. Wyszukiwanie FULLTEXT Realizacja podstawowego wyszukiwania FULLTEXT W rozdziale 5. przedstawiłem słowo kluczowe LIKE umożliwiające proste porównania łańcuchów, Po założeniu indeksu FULLTEXT możesz na przykład: wydawać zapytania przy użyciu funkcji MATCH i AGAINST w wyrażeniach warunkowych WHERE: SELECT * FROM users WHERE last_name LIKE 'Kowalsk%'; SELECT * FROM tabela WHERE MATCH (kolumna) W ten sposób nie wykonamy jednak wyszukiwań AGAINST('poszukiwane_słowa') z zastosowaniem wielu słów. Aby stało się to możliwe, wprowadzono wyszukiwania FULLTEXT. MySQL zwróci pasujące rekordy począwszy od spełniających warunek wyszukiwania Wyszukiwania FULLTEXT wymagają obecności w największym stopniu. Podczas wyszukiwania indeksu FULLTEXT, który można założyć jedynie stosowane są następujące reguły: na tabelach typu MyISAM. W następnych przykładach Łańcuchy rozbijane są na poszczególne będę używać tabeli messages bazy forum. Jeśli słowa. utworzona przez Ciebie tabela messages nie jest typu Słowa krótsze niż 4-znakowe są ignorowane. MyISAM i (lub) nie ma indeksu FULLTEXT założonego na kolumnach body i subject, wykonaj kroki podane Słowa często używane są ignorowane. na kilku poprzednich stronach, aby to zmienić. Jeśli ponad połowa rekordów spełnia Wskazówki warunek wyszukiwania, to nie jest zwracany żaden rekord. Wyszukiwanie FULLTEXT Wstawianie rekordów do tabel, na których założono indeks FULLTEXT, może być znacznie Zwłaszcza ostatnia reguła jest zaskakująca wolniejsze ze względu na skomplikowaną dla wielu użytkowników, którzy rozpoczynają naturę tego indeksu. dopiero przygodę z wyszukiwaniami FULLTEXT i dziwią się, dlaczego nie zwracają one żadnych Indeks FULLTEXT możemy zakładać na wielu wyników. Jeśli wypełnisz tabelę zbyt małą kolumnach, jeśli wszystkie mają być liczbą rekordów, to MySQL nie zwróci przeszukiwane. właściwych wyników. Wyszukiwania FULLTEXT mogą służyć do implementacji prostych usług wyszukiwania. Ponieważ jednak indeks FULLTEXT stosuje się do jednej tabeli, to usługi wyszukiwania informacji w wielu tabelach wymagają zastosowania bardziej zaawansowanych rozwiązań. 206
  • 38. Zaawansowany SQL i MySQL Aby wykonać wyszukiwanie FULLTEXT: Ten prosty przykład zwróci wynik pod warunkiem, że co najmniej jeden rekord i mniej 1. Wypełnij tabelę messages dużą ilością niż połowa rekordów tabeli messages zawiera danych — zwłaszcza w polu body. słowo tabela w polu body lub subject. Zwróć Możesz użyć w tym celu poleceń INSERT uwagę, że kolumny, do których odwołuje się ściągniętych z serwera ftp. MATCH, muszą być tymi samymi kolumnami, jakie podałeś, tworząc indeks FULLTEXT. W tym 2. Wykonaj proste wyszukiwanie FULLTEXT przykładzie mogłeś zatem użyć albo body, dla słowa skrypt (patrz rysunek 6.34). subject, albo subject, body, ale nie samych body SELECT subject, body FROM messages lub subject (patrz rysunek 6.35). WHERE MATCH (body, subject) AGAINST ('skrypt'); Rysunek 6.34. Podstawowe wyszukiwanie FULLTEXT Wyszukiwanie FULLTEXT Rysunek 6.35. Zapytanie FULLTEXT możesz wykonać jedynie na tej samej kolumnie lub kombinacji kolumn, dla której utworzyłeś indeks FULLTEXT. W tym przypadku zapytanie zakończy się błędem, mimo że kombinacja kolumn body i subject ma indeks FULLTEXT 207
  • 39. Rozdział 6. 3. Wykonaj to samo wyszukiwanie FULLTEXT, Wskazówki pokazując dodatkowo stopień spełnienia Pamiętaj, że jeśli wyszukiwanie FULLTEXT warunku przez poszczególne rekordy (patrz rysunek 6.36). nie zwróci żadnych rekordów, to albo żaden rekord nie spełnia warunku wyszukiwania, SELECT subject, body, albo spełnia go ponad połowa rekordów. MATCH (body, subject) AGAINST('skrypt') AS R Dla uproszczenia wszystkie zapytania FROM messages WHERE MATCH (body, subject) przedstawione w tym podrozdziale AGAINST('skrypt'); zapisałem jako najprostsze polecenia SELECT. Wyszukiwania FULLTEXT można też używać Jeśli użyjesz tego samego wyrażenia w bardziej skomplikowanych zapytaniach MATCH...AGAINST jako wybieranej wartości, czy złączeniach. to pokazany zostanie również stopień spełnienia warunku przez rekordy. MySQL zawiera w kodzie źródłowym listę kilkuset słów pospolitych, które są 4. Wykonaj wyszukiwanie FULLTEXT stosując kilka ignorowane w wyszukiwaniach FULLTEXT. słów (rysunek 6.37). Minimalną długość wyszukiwanego słowa SELECT subject, body FROM messages (wynoszącą domyślnie 4 znaki) można WHERE MATCH (body, subject) konfigurować. AGAINST('projekt formularz'); Domyślnie wyszukiwania FULLTEXT W tym przypadku rekord spełni warunek nie rozróżniają małych i wielkich liter. wyszukiwania, jeśli pole subject lub body Wyszukiwanie FULLTEXT będzie zawierać jedno z podanych słów. Rekord zawierający oba słowa uzyska wyższy stopień spełnienia warunku. Rysunek 6.36. Możesz również zobaczyć stopień spełniania warunku wyszukiwania przez poszczególne rekordy Rysunek 6.37. Wyszukiwanie FULLTEXT można także stosować dla wielu słów 208
  • 40. Zaawansowany SQL i MySQL Wyszukiwania FULLTEXT Znak maski (*) umożliwia wyszukiwanie różnych w trybie Boolean wariantów słowa. Na przykład zastosowanie go w słowie bezpiecz* spowoduje wyszukanie rekordów Bardziej zaawansowane wyszukiwania FULLTEXT zawierających słowa bezpieczny, bezpieczeństwo można wykonywać, korzystając z trybu i tym podobnych. Dwa kolejne operatory Boolean. W trybie tym używamy wyrażenia umożliwiają określenie, że dane słowo jest mniej (<) IN BOOLEAN MODE wewnątrz klauzuli AGAINST: lub bardziej (>) ważne. Znaki cudzysłowu pozwalają SELECT * FROM tabela WHERE wyszukiwać całe frazy, a nawiasy — tworzyć MATCH(kolumny) podwyrażenia. AGAINST('poszukiwane_słowa' IN BOOLEAN MODE) Poniższe zapytanie wyszuka rekordy zawierające W trybie Boolean możemy stosować szereg frazę serwer WWW oraz słowo html. Obecność operatorów (tabela 6.10) określających sposób słowa JavaScript obniży wartość rekordu jako traktowania każdego wyszukiwanego słowa: wyniku wyszukiwania. SELECT * FROM tabela WHERE SELECT * FROM tabela WHERE MATCH (kolumny) AGAINST('>"serwer WWW" +html MATCH(kolumny) ~JavaScript' IN BOOLEAN MODE) AGAINST('+baza -mysql' IN BOOLEAN MODE) W tym przykładzie rekord zostanie wybrany, W trybie Boolean pojawiają się następujące różnice w sposobie działania wyszukiwania FULLTEXT: jeśli zawiera słowo baza i nie zawiera słowa mysql. Jako słabszą formę operatora Jeśli słowo nie jest poprzedzone żadnym reprezentowanego przez znak minus ( -) operatorem, to jest opcjonalne, ale podnosi możemy stosować tyldę (~). Oznacza ona, wartość rekordu, który je zawiera. Wyszukiwanie FULLTEXT że rekord może zawierać dane słowo, Wyniki są zwracane nawet wtedy, gdy ponad ale wtedy w mniejszym stopniu spełnia połowa rekordów spełnia warunek warunek wyszukiwania. wyszukiwania. Wyniki nie są automatycznie sortowane na podstawie stopnia, w jakim spełniają warunek Tabela 6.10. Operatory umożliwiające wyszukiwania. precyzyjniejsze wyszukiwanie FULLTEXT Operatory dostępne w trybie Boolean Z uwagi na tę ostatnią właściwość można samodzielnie posortować rekordy według Operator Znaczenie stopnia w jakim spełniają warunek wyszukiwania, + Rekord musi zawierać słowo poprzedzone co zaprezentuję w kilku następnych krokach. tym operatorem. W przypadku wyszukiwań w trybie Boolean nadal - Rekord nie może zawierać słowa poprzedzonego tym operatorem. obowiązuje zasada, że słowa krótsze niż 4-znakowe ~ Słowo poprzedzone tym operatorem obniża są ignorowane. Nie zmienia tego użycie operatora wartość rekordu jako wyniku wyszukiwania. +, na przykład słowo +php zostanie zignorowane. * Maska wyszukiwania. < Zmniejsza znaczenie słowa. > Zwiększa znaczenie słowa. "" Rekord musi zawierać frazę umieszczoną w znakach cudzysłowu. () Tworzy podwyrażenie. 209
  • 41. Rozdział 6. Aby wykonać wyszukiwanie FULLTEXT 2. Wykonaj zapytanie wyszukujące w trybie Boolean: wiadomości dotyczące tabel ze szczególnym uwzględnieniem 1. Wykonaj proste wyszukiwanie FULLTEXT różnych zawierających termin normalizacja przypadków słowa baza (bazy, bazie itp.) (patrz rysunek 6.39). (patrz rysunek 6.38). SELECT subject, body FROM messages SELECT subject, body FROM WHERE MATCH(body, subject) messages WHERE MATCH(body, subject) AGAINST ('>formularz* +skrypt*' AGAINST('baz*' IN BOOLEAN MODE) G IN BOOLEAN MODE)G Słowo baza może pojawić się w wiadomościach Zapytanie to najpierw wyszukuje forum w wielu różnych przypadkach takich wszystkie rekordy zawierające słowo jak bazy lub bazie. Powyższe zapytanie wyszuka skrypt* (skryptu, skrypty, …) i formularz* rekordy zawierające te przypadki dzięki (formularz, formularza, formularzy, …). zastosowaniu znaku maski (*). Obecność terminu skrypt* jest wymagana Dodatkowo zastosowałem znacznik G, (na co wskazuje operator +), natomiast aby łatwiej przeanalizować wyniki. wyróżnione zostają rekordy zawierające termin formularz* (na co wskazuje operator >). Wyszukiwanie FULLTEXT Rysunek 6.38. Proste wyszukiwanie FULLTEXT w trybie BOOLEAN Rysunek 6.39. To wyszukiwanie dotyczy wariantów dwóch różnych słów, z których jedno ma wyższy priorytet 210
  • 42. Zaawansowany SQL i MySQL Wskazówki W MySQL 5.1.7 wprowadzono jeszcze jeden tryb wyszukiwań FULLTEXT: tryb języka naturalnego. Jeśli nie wybierzesz innego trybu (np. Boolean), to jest on trybem domyślnym. Modyfikator WITH QUERY EXPANSION pozwala zwiększyć liczbę zwracanych wyników. Optymalizacja bazy danych Zapytania z tym modyfikatorem wykonują Efektywność działania bazy danych zależy w rzeczywistości dwa wyszukiwania, ale zwracają głównie od jej struktury i indeksów. Tworząc jeden zbiór wyników. Drugie wyszukiwanie bazę, powinieneś spróbować: bazuje na terminach wyszukanych dodatkowo w najlepszych wynikach pierwszego Wybrać najlepszy silnik przechowywania. wyszukiwania. Pozwala to znaleźć dodatkowe Używać jak najmniej pojemnego typu rekordy, ale nie zawsze odpowiadają one danych dla każdej kolumny. początkowym kryteriom wyszukiwania. Definiować kolumny jako NOT NULL tam, gdzie to możliwe. Używać wartości całkowitych jako kluczy głównych. Uważnie definiować indeksy, wybierając odpowiedni typ oraz stosując je Wyszukiwanie FULLTEXT dla właściwych kolumn. Ograniczać indeksy do pewnej liczby znaków, jeśli to możliwe. Oprócz tych wskazówek warto zastosować dwie proste techniki optymalizacji baz danych. Jednym ze sposobów poprawy efektywności działania MySQL-a jest wykonanie polecenia OPTIMIZE dla tabel. Polecenie to usuwa wolne przestrzenie i przywraca wysoką efektywność działania tabel. OPTIMIZE TABLE tabela; Wykonanie tego polecenia jest szczególnie zalecane po modyfikacji tabeli za pomocą polecenia ALTER. Aby zwiększyć wydajność wykonywanego zapytania, warto zrozumieć, w jaki sposób serwer MySQL-a je przetwarza. W tym celu należy posłużyć się słowem kluczowym języka SQL o nazwie EXPLAIN. Informacje na temat działania zapytań znajdziesz w podręczniku MySQL-a. 211
  • 43. Rozdział 6. Wykonywanie transakcji Po zatwierdzeniu lub wycofaniu zapytań transakcja jest uznawana za zakończoną Transakcja bazodanowa to seria zapytań i MySQL wraca do trybu automatycznego wykonywanych podczas jednej sesji. Przypuśćmy, zatwierdzania (ang. autocommit). Oznacza to, że wstawiamy rekord do jednej tabeli, inny rekord że wszystkie zapytania są natychmiast do drugiej tabeli, a potem wykonujemy aktualizację. realizowane. Aby rozpocząć następną Bez transakcji każda operacja jest realizowana transakcję, wystarczy ponownie wpisać START natychmiast i nie można jej cofnąć. Jeśli użyjemy TRANSACTION. transakcji, będziemy mogli ustawić punkt początkowy i końcowy, a następnie zatwierdzić Trzeba wiedzieć, że niektórych typów transakcji lub wycofać wszystkie zapytania (jeśli, na przykład, nie da się wycofać; dotyczy to w szczególności zawiedzie jedno zapytanie, będzie można wycofać zapytań, które tworzą, modyfikują, opróżniają wszystkie). lub usuwają tabele albo tworzą lub usuwają bazy danych. Co więcej, wykonanie takiego Transakcje są często potrzebne w interakcjach zapytania skutkuje zatwierdzeniem finansowych, nawet tak podstawowych jak przelew i zakończeniem bieżącej transakcji. 100 złotych z jednego konta na drugie. Proces ten wydaje się prosty, ale w rzeczywistości składa się Powinieneś też pamiętać, że transakcje są z kilku etapów: specyficzne dla każdego połączenia. Zatem jeden użytkownik klienta mysql dokonuje Potwierdzenia, że na pierwszym koncie znajduje innej transakcji niż użytkownik drugiego się przynajmniej 100 złotych. klienta, a obie te transakcje są niezależne Zmniejszenia stanu pierwszego konta od realizowanych przez skrypt PHP. Wykonywanie transakcji o 100 złotych. To powiedziawszy, zaprezentuję bardzo prosty Zwiększenia stanu drugiego konta o 100 złotych. przykład użycia transakcji w kliencie mysql. W rozdziale 17. pokażę, jak realizować Sprawdzenia, czy udało się zwiększyć stan transakcje z wykorzystaniem skryptów PHP. drugiego konta. Jeśli którakolwiek z tych operacji się nie powiedzie, należy cofnąć je wszystkie. Jeśli na przykład nie uda się umieścić pieniędzy na drugim koncie, powinny one wrócić na pierwsze. Odbywa się to do momentu, w którym uda się przeprowadzić całą transakcję. Aby korzystać z transakcji w MySQL-u, trzeba posługiwać się tabelami InnoDB (lub silnikiem tego typu). W celu rozpoczęcia nowej transakcji w kliencie mysql należy wpisać: START TRANSACTION; Na zakończenie transakcji należy wydać instrukcję COMMIT, aby zatwierdzić wszystkie zapytania, albo ROLLBACK, aby je wycofać. 212
  • 44. Zaawansowany SQL i MySQL Aby wykonać transakcję, Oczywiście trudno uznać to za kompletny należy wykonać poniższe czynności: projekt tabeli czy bazy danych. Zasady normalizacji nakazywałyby rozdzielić imię 1. Uruchomić klienta mysql i wybrać bazę i nazwisko użytkownika na dwie kolumny, danych test. a nawet umieścić je w innej tabeli. Jednakże Ponieważ jest to tylko przykład, tabela ta w zupełności wystarczy do naszych wykorzystam hipotetyczną bazę danych test. celów. 2. Utworzyć nową tabelę accounts Najważniejszym aspektem definicji tabeli jest (patrz rysunek 6.40). określenie mechanizmu InnoDB, który obsługuje CREATE TABLE accounts ( transakcje. id INT UNSIGNED NOT NULL 3. Wypełnić tabelę danymi. AUTO_INCREMENT, name VARCHAR(40) NOT NULL, INSERT INTO accounts (name, balance) balance DECIMAL(10,2) NOT NULL VALUES ('Beata Piechota', 5460.30), DEFAULT 0.0, ('Dawid Wójcik', 909325.24), PRIMARY KEY (id)) ('Ilona Machnik', 892.00); ENGINE=InnoDB; Można użyć dowolnie wybranych nazwisk i wartości. Należy zauważyć, że MySQL automatycznie zatwierdzi to zapytanie, ponieważ nie została jeszcze rozpoczęta żadna transakcja. Rysunek 6.40. Nowa tabela utworzona w bazie danych test posłuży Wykonywanie transakcji do zademonstrowania transakcji 213
  • 45. Rozdział 6. 4. Rozpocząć transakcję i pobrać bieżącą zawartość tabeli (patrz rysunek 6.41). START TRANSACTION; SELECT * FROM accounts; 5. Podjąć 100 złotych z konta Dawida Wójcika (albo dowolnego innego użytkownika). UPDATE accounts Rysunek 6.41. Rozpoczęto transakcję i wyświetlono SET balance=(balance-100) wszystkie rekordy znajdujące się w tabeli WHERE id=2; Instrukcja UPDATE, odrobina matematyki i klauzula WHERE pozwalają zmniejszyć stan konta o 100 złotych. Choć MySQL informuje, że zmodyfikowany został jeden wiersz, efekt nie będzie trwały, dopóki transakcja nie zostanie zatwierdzona. 6. Wpłacić 100 złotych na konto Beaty Piechoty: UPDATE accounts SET balance=(balance+100) WHERE id=1; Rysunek 6.42. Wykonano dwa zapytania Jest to przeciwieństwo operacji wykonanej i wyświetlono wyniki w etapie 5., co odzwierciedla przelewanie Wykonywanie transakcji 100 złotych z jednego konta na drugie. 7. Sprawdzić wyniki (patrz rysunek 6.42). SELECT * FROM accounts; Jak widać na rysunku, na jednym koncie jest teraz o 100 złotych więcej, a na drugim o 100 złotych mniej niż na początku (patrz rysunek 6.41). 214
  • 46. Zaawansowany SQL i MySQL 8. Wycofać transakcję. ROLLBACK; Aby zademonstrować wycofywanie transakcji, unieważniam wykonane wcześniej zapytania. Instrukcja ROLLBACK przywraca bazę danych do stanu sprzed rozpoczęcia transakcji. Instrukcja ta kończy jednocześnie transakcję, przełączając MySQL-a z powrotem do trybu automatycznego zatwierdzania. Rysunek 6.43. Ponieważ użyto instrukcji 9. Sprawdzić wyniki (patrz rysunek 6.43). ROLLBACK, wykonane wcześniej zapytania SELECT * FROM accounts; zostały wycofane Zapytanie powinno zwrócić zawartość tabeli sprzed rozpoczęcia transakcji. 10. Powtórzyć etapy 4. – 6. Aby sprawdzić, co się stanie w razie zatwierdzenia transakcji, należy ponownie wykonać dwa zapytania UPDATE. Należy pamiętać o rozpoczęciu nowej transakcji, ponieważ w przeciwnym razie zapytania zostaną Wykonywanie transakcji automatycznie zatwierdzone! 11. Zatwierdzić transakcję i sprawdzić wyniki (patrz rysunek 6.44). COMMIT; Rysunek 6.44. Instrukcja COMMIT SELECT * FROM accounts; utrwala rezultaty transakcji Po wydaniu instrukcji COMMIT transakcja zostanie zatwierdzona, co oznacza, że wszystkie zmiany staną się trwałe. Instrukcja ta jednocześnie kończy transakcję, przełączając MySQL-a z powrotem do trybu automatycznego zatwierdzania. 215
  • 47. Rozdział 6. Wskazówki Jedną z największych zalet transakcji jest to, że zapewniają one ochronę przed zdarzeniami losowymi, takimi jak awaria serwera. Transakcja jest albo w całości zatwierdzana, albo ignorowana. Aby wyłączyć tryb automatycznego zatwierdzania w serwerze MySQL-a, należy wpisać: SET AUTOCOMMIT=0; Nie trzeba będzie wówczas wydawać instrukcji START TRANSACTION, a wszystkie wykonane zapytania zostaną zrealizowane dopiero po wpisaniu instrukcji COMMIT (albo użyciu zapytania CREATE, ALTER itp.). W transakcjach można tworzyć punkty zapisu: SAVEPOINT nazwa_punktu_zapisu; Funkcja ta umożliwia wycofanie transakcji do określonego punktu zapisu: Wykonywanie transakcji ROLLBACK TO SAVEPOINT nazwa_punktu_zapisu; 216