Czym jest normalizacja, jak wyglądają pierwsza, druga i trzecia postać normalna na jednym przykładzie sklepowego arkusza i jak rozpoznać postać normalną tabeli pokazanej w pytaniu. Lekcja 7.4 kursu INF.03.
Normalizacja to proces organizowania danych w bazie, polegający na wyeliminowaniu nadmiarowych danych oraz niespójnych zależności: dzielisz jedną wielką tabelę na kilka mniejszych tak, żeby każda informacja była zapisana raz i żeby zmiana jednej rzeczy wymagała poprawki w jednym miejscu. Na egzaminie pisemnym wraca w dwóch kształtach: pytanie o samą definicję i pytanie z rysunkiem tabeli, w którym trzeba powiedzieć, w której postaci normalnej ta tabela jest. Cała lekcja idzie za jednym przykładem: arkusz kalkulacyjny sklepu zamienia się krok po kroku w bazę z pięcioma tabelami.
Arkusz, od którego zaczynamy
Sklep przez rok prowadził zamówienia w arkuszu kalkulacyjnym. Jeden wiersz to jedno zamówienie, wszystko w jednej tabeli.
[ ARKUSZ PRZED NORMALIZACJĄ ]
nr
klient
miasto
kod
telefony
produkty
ceny
10
Anna
Kraków
30-001
600100100, 600100101
Monitor 24
650
11
Anna
Kraków
30-001
600100100, 600100101
Klawiatura, Mysz
120, 45
12
Piotr
Gdańsk
80-001
500200200
Kabel HDMI
25
Taka struktura z jedną tabelą to model jednorodny, zwany też płaskim. Działa, dopóki wierszy jest kilkanaście. Przy kilku tysiącach zaczyna się psuć, i to w sposób, który podstawa programowa i egzamin nazywają po imieniu.
Nadmiarowość i trzy anomalie
Redundancja (redundancy, nadmiarowość) to ta sama informacja zapisana w bazie więcej niż raz. Tutaj widać ją gołym okiem: imię Anny, jej miasto, kod pocztowy i oba telefony powtarzają się w każdym jej zamówieniu. Zajmowanie miejsca to najmniejszy problem. Gorsze są trzy anomalie, czyli sytuacje, w których zwykła operacja na danych psuje bazę.
›
Anomalia aktualizacji: Anna przeprowadza się do Gdyni, więc trzeba poprawić miasto w KAŻDYM jej wierszu. Jeżeli jeden zostanie pominięty, baza twierdzi jednocześnie, że Anna mieszka w Krakowie i w Gdyni. To jest właśnie niespójność z definicji normalizacji.
›
Anomalia wstawiania: do sklepu zapisuje się nowy klient, który jeszcze nic nie kupił. Nie ma go gdzie wpisać, bo wiersz istnieje tylko razem z zamówieniem.
›
Anomalia usuwania: ktoś kasuje zwrócone zamówienie 12. Razem z nim znika jedyny ślad po Piotrze: jego miasto, kod i telefon.
Za wszystkimi trzema stoi jedno pojęcie. Zależność funkcyjna (functional dependency) to sytuacja, w której znając wartość jednej kolumny, znasz wartość drugiej. Znając numer zamówienia, znasz jego klienta. Znając klienta, znasz jego miasto. Znając kod pocztowy, znasz miasto. Normalizacja polega na tym, żeby każdą taką zależność zapisać w osobnej tabeli, w której lewa strona zależności jest kluczem głównym.
1NF: jedna wartość w jednym polu
Pierwsza postać normalna (1NF) wymaga trzech rzeczy: każde pole ma dokładnie JEDNĄ wartość (atomowość), nie ma powtarzających się grup kolumn w rodzaju telefon1, telefon2, telefon3, a tabela ma klucz główny. Arkusz łamie pierwszy warunek w trzech kolumnach naraz: telefony, produkty i ceny trzymają listy rozdzielone przecinkami.
Listę rozbija się na wiersze albo na osobną tabelę. Produkty i ceny idą na wiersze: jedno zamówienie zajmuje teraz tyle wierszy, ile ma pozycji. Telefony wychodzą do własnej tabeli, bo z zamówieniem nie mają nic wspólnego.
nr
klient
miasto
kod
produkt
cena
ilosc
10
Anna
Kraków
30-001
Monitor 24
650
1
11
Anna
Kraków
30-001
Klawiatura
120
2
11
Anna
Kraków
30-001
Mysz
45
1
12
Piotr
Gdańsk
80-001
Kabel HDMI
25
3
Sam nr nie jest już kluczem głównym, bo numer 11 stoi w dwóch wierszach. Wiersz identyfikuje dopiero para nr i produkt, czyli klucz złożony. Obok powstaje druga tabela, w której jeden wiersz to jeden numer telefonu:
klient
numer
Anna
600100100
Anna
600100101
Piotr
500200200
Kolumna klient zmieni się w klient_id, kiedy klienci dostaną własną tabelę z numerami. Tabela jest w 1NF, a mimo to Anna nadal siedzi w trzech wierszach. Nadmiarowość została, więc to nie koniec.
2NF: zależność od całego klucza
Druga postać normalna (2NF) to 1NF plus warunek: każdy atrybut niekluczowy zależy od CAŁEGO klucza głównego, a nie od jego części. Dotyczy wyłącznie tabel z kluczem złożonym, bo tylko taki klucz ma części. Tabela z kluczem jednokolumnowym, która jest w 1NF, jest już w 2NF.
Klucz to tutaj nr plus produkt. Sprawdzamy po kolei każdą pozostałą kolumnę:
Kolumna
Od czego naprawdę zależy
Wniosek
klient, miasto, kod
od samego nr
zależność od części klucza, do wyniesienia
cena
od samego produkt
zależność od części klucza, do wyniesienia
ilosc
od nr i produkt razem
zostaje na miejscu
Kolumny zależne od części klucza wyprowadza się do tabel, w których ta część jest kluczem głównym. Powstają trzy tabele zamiast jednej:
Produkty przestały być tekstem wpisywanym za każdym razem od nowa i stały się słownikiem z własnymi numerami, więc pozycja wskazuje na nie kluczem obcym produkt_id. Skoro sklep opisuje też, do jakiej grupy towar należy, kolumna kategoria trafia do produkt razem z nazwą i ceną. Zmiana ceny monitora to teraz jedno polecenie UPDATE na jednym wierszu.
3NF: koniec zależności przechodnich
Trzecia postać normalna (3NF) to 2NF plus warunek: żaden atrybut niekluczowy nie zależy od innego atrybutu niekluczowego. Taka zależność „na dwa skoki" nazywa się zależnością przechodnią.
W tabeli zamowienie kluczem jest nr. Kolumny miasto i kod nie mówią nic o zamówieniu, mówią o kliencie: znając nr, znasz klient, a znając klient, znasz jego miasto. Klient wychodzi więc do własnej tabeli, a w zamówieniu zostaje po nim klucz obcy.
Ta sama reguła działa piętro niżej. W tabeli klient miasto zależy od kodu pocztowego, a nie od numeru klienta: kod 30-001 to zawsze Kraków. Purysta wyniesie to do tabeli kod_pocztowy(kod PK, miasto). W małych bazach, także w tych z arkuszy egzaminacyjnych, zwykle zostawia się miasto przy kliencie i na tym poprzestaje, bo osobna tabela na kody pocztowe wymaga utrzymywania całego ich spisu. Tak samo z kategorią: jeżeli kategoria ma własne dane, na przykład opis albo stawkę podatku, robi się z niej tabela kategoria, a produkt dostaje kategoria_id.
Po lewej jedna tabela zamowienia_arkusz z powtórzonymi danymi klienta i produktami wpisanymi po przecinku, po prawej cztery tabele po normalizacji połączone strzałkami po kluczach
To jest dokładnie schemat bazy sklep, na której stoi cały dział o SQL, z jednym uproszczeniem: tam zamowienie trzyma produkt_id i ilosc bezpośrednio, bez tabeli pozycja, bo w kursie jedno zamówienie ma jeden produkt. Taka baza ma wszystkie cechy relacyjnej bazy danych: dane siedzą w tabelach, każdy wiersz identyfikuje klucz główny o wartości unikalnej i różnej od NULL, tabele wiążą klucze obce, a każda informacja jest zapisana w jednym miejscu.
Wykonaj zapytanie, które składa trzy tabele z powrotem w jeden arkusz, i porównaj wynik z tabelą z początku lekcji:
Postaci normalnych jest więcej: po 3NF idzie postać Boyce'a i Codda (BCNF), a za nią 4NF i 5NF. Do egzaminu INF.03 potrzebne są trzy pierwsze i ich nazwy w kolejności.
W drugą stronę działa denormalizacja, czyli świadome cofnięcie części podziału. Klasyczny przykład jest w tym samym sklepie: cena produktu z czasem się zmienia, a faktura sprzed roku ma pokazywać cenę sprzed roku, więc do tabeli pozycja kopiuje się cenę z chwili zakupu. Formalnie to nadmiarowość, w praktyce jedyny sposób na cenę historyczną.
Pułapka: denormalizacja jest wyjątkiem, którego na egzaminie się nie zgaduje. Gdy pytanie brzmi „jak powinna wyglądać ta baza", oczekiwaną odpowiedzią jest baza znormalizowana do trzeciej postaci normalnej.
Na egzaminie
Pytanie pisemne pokazuje jedną tabelę z danymi i pyta, co można powiedzieć o jej normalizacji. Zadaj sobie trzy pytania, zawsze w tej kolejności:
1.
Czy w którymś polu jest lista wartości po przecinku albo czy powtarza się grupa kolumn (telefon1, telefon2)? Jeżeli tak, tabela nie jest nawet w 1NF.
2.
Czy klucz główny jest złożony i któraś kolumna zależy tylko od jego części? Jeżeli tak, tabela jest w 1NF, ale nie w 2NF.
3.
Czy któraś kolumna niekluczowa zależy od innej kolumny niekluczowej, na przykład miasto od kodu pocztowego? Jeżeli tak, tabela jest w 2NF, ale nie w 3NF.
Pierwsze „nie" kończy sprawdzanie: tabela jest w tej postaci, przed którą się zatrzymałeś. Dwa pozostałe kształty pytań to definicja („proces eliminujący nadmiarowe dane i niespójne zależności" to normalizacja) i pytanie o pojedynczy warunek: atomowości pól wymaga pierwsza postać normalna, a zależność przechodnią usuwa trzecia.
W zadaniu praktycznym normalizacji się nie przeprowadza, bo baza z arkusza jest już podzielona na tabele i podana razem ze schematem relacji. Warto jednak wiedzieć, skąd ten podział się wziął: właśnie dlatego dane jednego zamówienia leżą w trzech tabelach i dlatego jedna z kwerend musi „wykorzystywać relację", czyli łączyć tabele po kluczu obcym.
Pułapka: kolejność etapów projektowania bazy z pytań egzaminacyjnych brzmi: określenie zbioru danych, podział na tabele, określenie kluczy podstawowych, określenie relacji. Normalizacja siedzi w kroku drugim i trzecim, a nie na końcu.
Ściąga
Postać
Warunek
Sygnał, że tabela go łamie
Co zrobić
1NF
jedna wartość w polu, brak powtarzających się grup kolumn, jest klucz główny
wartości po przecinku w komórce, kolumny telefon1 i telefon2
rozbić listę na osobne wiersze albo na osobną tabelę
2NF
1NF plus każda kolumna niekluczowa zależy od całego klucza
klucz złożony, a kolumna zależy tylko od jednej jego części
wynieść tę kolumnę do tabeli, w której ta część jest kluczem głównym
3NF
2NF plus brak zależności przechodnich
kolumna niekluczowa zależy od innej niekluczowej, miasto od kodu
wynieść obie do osobnej tabeli, zostawić klucz obcy