Przystępując do procesu projektowania nowej bazy danych, czyli tworzenia nowego modelu danych, należy dążyć do zapewnienia jego podstawowych cech:
Wszelkie działania mające na celu realizację powyższych założeń powinny zostać podjęte na samym początku procesu projektowania, w ścisłym kontakcie z przyszłym użytkownikiem. Po skonstruowaniu modelu danych użytkownicy powinni rozumieć utworzony model danych i po dokładnym przeanalizowaniu wszystkich szczegółów, biorąc za to odpowiedzialność, zatwierdzić go. Z kolei projektant bazy danych musi traktować uzgodniony z użytkownikami model danych, jako wierny obraz rzeczywistości i dla tego modelu budować bazę danych i wszystkie aplikacje z nią współpracujące.
Postulat normalizacji daje się wyrazić w następujący sposób:
Każdy fakt przechowywany w bazie danych powinien być wyrażalny w niej tylko na jeden sposób.
Przedstawienie zasad normalizacji wymaga zastosowania formalnego, matematycznego modelu relacji. W wersji uproszczonej zostanie on zaprezentowany w dalszej części tego wykładu. Konieczność przeprowadzenia normalizacji, oraz jej zasady wprowadzimy najpierw poprzez przykłady.
Jeżeli w modelu danych istnieje możliwość wystąpienia problemów podobnych do wynikających z powyższych przykładów, oznacza to istnienie błędów w konstrukcji takiego modelu. Mówimy tu o przyjęciu w modelu złych schematów relacji (tabel).
Problem złych schematów tabel zaprezentujemy na dwóch przykładach. Klucz główny schematów będzie zaznaczany pogrubioną czcionką.
Problem złych schematów tabel zaprezentujemy na dwóch przykładach. Klucz główny schematów będzie zaznaczany pogrubioną czcionką.
Schemat relacji definiowany jest następująco:
Dostawcy_Towary = {Nazwa_dostawcy, Nazwa_towaru, Adres_dostawcy, Cena}
Implementacją tego schematu jest tabela, z przykładowymi danymi.
Tabela 7.1 Relacja opisana przez schemat Dostawcy_Towary
Nazwa_dostawcy | Adres_dostawcy | Nazwa_Towaru | Cena |
---|---|---|---|
Kowalski | Krótka 1 | Telewizor | 3000 |
Kowalski | Krótka 1 | Pralka | 2000 |
Jaworski | Długa 12 | Lodówka | 2500 |
Jaworski | Długa 12 | Zmywarka | 2800 |
Kowalski | Krótka 1 | Lodówka | 1800 |
Piotrowski | Polna 33 | Laptop | 4500 |
Analizując przykładowe dane zapisane według powyższego schematu, łatwo jest zidentyfikować jego wady, które utrudnią eksploatację danych i uniemożliwią realizację postulatów opisanych na początku tego rozdziału.
Przyczyną powstania tych wad jest zły schemat relacji, który łączy w jednej encji atrybuty dwóch różnych rodzajów (klas) obiektów (encji) – dostawców i towarów.
Rozwiązanie stanowi poprawienie schematu, polegające na rozłożeniu wyjściowego schematu na dwa. Każdy z nowych schematów reprezentuje osobny typ obiektów, czyli odpowiednio dostawców i towary.
Dostawcy = {Nazwa_dostawcy, Adres}
Towary = {Nazwa_dostawcy, Nazwa_towaru, Cena}
Implementacją tych schematów będą dwie tabele, zawierające rozdzielone dane.
Tabela 7.2 Dane dostawców.
Nazwa_dostawcy | Adres_dostawcy |
---|---|
Kowalski | Krótka 1 |
Kowalski | Krótka 1 |
Jaworski | Długa 12 |
Jaworski | Długa 12 |
Kowalski | Krótka 1 |
Jaworski | Polna 33 |
Tabela 7.3 Dane towarów.
Nazwa_dostawcy | Nazwa_Towaru | Cena |
---|---|---|
Kowalski | Telewizor | 3000 |
Kowalski | Pralka; | 2000 |
Jaworski | Lodówka; | 2500 |
Jaworski | Zmywarka | 2800 |
Jaworski | Lodówka | 1800 |
Jaworski | Laptop | 4500 |
Schemat relacji definiowany jest następująco:
Pracownicy = {Id_pracownika, Nazwisko, Nazwa_uczelni, Adres}
Implementacją tego schematu jest tabela, z przykładowymi danymi.
Tabela 7.4 Relacja opisana przez schemat Pracownicy.
Id_pracownika | Nazwisko | Uczelnia | Adres_uczelni |
---|---|---|---|
102 | Kowalski | PJWSTK | Koszykowa 86 |
103 | Kalinowski | PW | Nowowiejska 24 |
112 | Jaworski | PJWSTK | Koszykowa 86 |
105 | Makowski | PJWSTK | Koszykowa 86 |
105 | Piotrowski | PW | Nowowiejska 24 |
Tak jak w poprzednim przykładzie, tutaj też możemy zaobserwować podobne wady jak poprzednio, mimo, że tym razem klucz główny jest jednoelementowy.
Przyczyną tych wad także jest zły schemat relacji, łączący w jednej encji dwa różne rodzaje (klas) obiektów (encji), czyli pracowników i uczelni.
Rozwiązaniem, tak jak i poprzednio, jest rozłożenie początkowego schematu na dwa, z których każdy reprezentuje osobny typ obiektów, czyli odpowiednio pracowników i uczelnie.
Pracownicy = {Id_pracownika, Nazwisko, Uczelnia}
Uczelnie = {Uczelnia, Adres}
Implementacją tych schematów będą także dwie tabele, zawierające rozdzielone dane.
Tabela 7.5 Dane pracowników:
Id_pracownika | Nazwisko | Uczelnia |
---|---|---|
102 | Kowalski | PJWSTK |
103 | Kalinowski | PW |
112 | Jaworski | PJWSTK |
105 | Makowski | PJWSTK |
121 | Piotrowski | PW |
Tabela 7.6 Dane uczelni:
Uczelnia | Adres_uczelni |
---|---|
PJWSTK | Koszykowa 86 |
PW | Nowowiejska 24 |
Przyczyny występowania błędów w schematach wyjaśnimy wprowadzając pojęcie zależności funkcyjnych częściowej i przechodniej.
Dla schematu:
Dostawcy_towary = {Nazwa_dostawcy, Nazwa_towaru, Adres_dostawcy, Cena}
kluczem jest para atrybutów: Nazwa_dostawcy i Nazwa_towaru, a atrybut Adres_dostawcy zależy od części klucza - od atrybutu Nazwa_dostawcy. Wartość atrybutu Nazwa_dostawcy jednoznacznie określa wartość atrybutu Adres_dostawcy, czyli znając nazwę dostawcy, znamy również jego adres.
Mówimy, że wartość atrybutu Adres zależy częściowo od klucza:
Nazwa_dostawcy -> Adres_dostawcy
a samą zależność nazywamy zależnością częściową. Po przeniesieniu atrybutów: Nazwa_dostawcy i Adres_dostawcy do osobnej encji, atrybut Nazwa_dostawcy staje się kluczem, a zależność częściowa Nazwa_dostawcy -> Adres_dostawcy staje się zależnością od całego klucza.
Rysunek 7.1 Rozłożenie "złego" schematu na dwa, nie zawierające zależności częściowych
Korekta złego schematu Dostawcy_towary poprzez rozłożenie go na dwa powiązane schematy Towary i Dostawcy.
Dla schematu tabeli:
Pracownicy = {Id_pracownika, Nazwisko, Uczelnia, Adres_uczelni}
Kluczem jest atrybut Id_pracownika, a atrybut Adres_uczelni zależy od innego atrybutu Uczelnia, który nie jest kluczem. Wartość atrybutu Uczelnia jednoznacznie określa wartość atrybutu Adres_uczelni, czyli znając nazwę uczelni, znamy także jej adres.
Mówimy w takim przypadku, że wartość atrybutu Adres zależy przechodnio od klucza:
Uczelnia -> Adres_uczelni
a samą zależność nazywamy zależnością przechodnią. Po przeniesieniu atrybutów: Nazwa_uczelni i Adres do osobnej encji, atrybut Nazwa_uczelni staje się kluczem, a zależność częściowa Nazwa_uczelni-> Adres staje się zależnością od całego klucza.
Rysunek 7.2 Rozłożenie "złego" schematu na dwa, nie zawierające zależności przechodnich.
Korekta złego schematu Pracownicy poprzez rozłożenie go na dwa powiązane schematy Pracownicy i Uczelnie.
Korektę schematów zawierających atrybuty zależne przechodnio lub częściowa, można opisać następująco:
Atrybut wzajemnie zależne przenieś do nowej encji, w której atrybut stojący po lewej stronie zależności jest kluczem. Utwórz związek encji nowej i wyjściowej, w którym nowa encja będzie encją nadrzędną (po stronie „jeden”). Jeżeli zależność była zależnością częściową, związek będzie identyfikujący.
Realizacja tego rozwiązania pokazana jest na powyższym rysunku.
Reasumując, istnienie zależności częściowych i przechodnich wskazuje, że schemat tabel ma niepoprawne właściwości. Poprawne są tylko zależności funkcyjne od całego klucza. Stwierdzenie istnienia w schemacie bazy danych takich zależności, wskazuje na konieczność rozłożenia istniejących schematów na takie, które opisują pojedyncze klasy obiektów, oraz wprowadzenie związków pomiędzy nimi.
Relacja jest abstrakcyjnym, matematycznym pojęciem zawierającym w sobie istotę modelu relacyjnego. Relacyjna baza danych to zbiór relacji.
Tabela jest konkretną reprezentacją relacji – jedna relacja ma (może mieć) wiele różnych reprezentacji za pomocą tabel.
W relacji kolejność wierszy i kolejność kolumn są nieistotne. Dwa wiersze w tabeli zawierające te same wartości są uznawane za identyczne, to znaczy za ten sam element relacji.
Schematem relacji nazywamy listę
R = {A1, A2, ...., An}
Gdzie A1, A2, ...., An są atrybutami (nazwami kolumn).
Na przykład:
Tabela 7,6 Relacja opisana przez schemat Loty
Flight | From | To | Departure | Arrival |
---|---|---|---|---|
BA0849 | WAW (Warsaw) | Htw (London) | 07:30 | 09:15 |
BA0847 | Htw (London) | WAW (Warsaw) | 12:25 | 14:00 |
AF1247 | WAW (Warsaw) | CDG (Paris) | 07:05 | 09:30 |
AF1246 | CDG (Paris) | WAW (Warsaw) | 18:40 | 20:55 |
LO0006 | WAW (Warsaw) | JFK (New York) | 12:50 | 16:20 |
LO0007 | JFK (New York) | WAW (Warsaw) | 18:40 | 09:05 +1 |
LH710 | FRA (Frankfurt) | NRT (Tokyo) | 13:45 | 07:40 +1 |
LH711 | NRT (Tokyo) | FRA (Frankfurt) | 09:45 | 14:25 |
LO3907 | WAW (Warsaw) | 08:30 | 09:20 |
Moglibyśmy zmienić kolejność wierszy w tabeli. Moglibyśmy zmienić kolejność kolumn w tej tabeli. I nie miałoby to żadnego znaczenia dla relacji, będącej zawartością tabeli. Będzie to ciągle ta sama relacja.
Każdemu atrybutowi A przyporządkowana jest dziedzina oznaczana przez Dom(A), czyli zbiór dopuszczalnych wartości atrybutu A.
Np:
Dom(Flight) = CHAR(10)
Dom(From) = CHAR(15)
Dom(To) = CHAR(15)
Dom(Departure) = DATE/TIME
Dom(Arrival) = DATE/TIME
Dziedziną relacji o schemacie:
R = {A1, A2,..., An}
nazywamy sumę dziedzin wszystkich atrybutów relacji
Dom(R) = Dom(A1) U Dom(A2) U ... U Dom(An)
gdzie znak „U” oznacza operację sumowania zbiorów.
Relacją o schemacie:
R = {A1, A2,..., An}
nazywamy skończony zbiór
r = {t1, t2,...,tm}
takich odwzorowań
ti: R -> Dom(R)
że dla każdego
j, 1 <= j <= n, ti(Aj) należy do dziedziny Dom(Aj)
Każde takie odwzorowanie t nazywa się krotką (lub wierszem).
Krotka odpowiada wierszowi (rekordowi) w tabeli. Można ją formalnie określić przez podanie wartości dla poszczególnych atrybutów np.
t(Flight) = BA0849
t(From) = Warsaw
t(To) = London
t(Departure) = 07:30
t(Arrival) = 09:15
Tabela 7.7 Graficzne przedstawienie opisanej krotki.
Flight | From | To | Departure | Arrival |
---|---|---|---|---|
BA0849 | WAW (Warsaw) | Htw (London) | 07:30 | 09:15 |
Ograniczeniem krotki t relacji r o schemacie R do zbioru atrybutów X z R nazywamy odwzorowanie będące ograniczeniem t do zbioru atrybutów X
t|x: X -> Dom(R)
to znaczy t|x(x) = t(x) dla x w X, a dla x w (R – X) wartość t|x(x) jest nieokreślona.
Na przykład, gdy:
X = {From, To}
to dla krotki t z poprzedniego przykładu
t|x (From) = Warsaw t|x (To) = London
Tabela 7.8 Graficzne przedstawienie ograniczenia krotki.
From | To |
---|---|
WAW (Warsaw) | Htw (London) |
Relacja r o schemacie R = {A1, A2,..., An} spełnia zależność funkcyjną
X -> Y (X, Y - podzbiory R)
jeśli dla każdych dwóch krotek t, u relacji r spełniony jest warunek:
Jeśli t|X = u|X to t|Y = u|Y
to znaczy, w ramach krotek relacji r wartości atrybutów zbioru X determinują jednoznacznie wartości atrybutów zbioru Y.
W przykładowej relacji Loty, wartości atrybutu Flight jednoznacznie identyfikują cały lot, a więc w szczególności jednoznacznie identyfikują wartości wszystkich atrybutów tej relacji:
Flight -> {From, To, Departure, Arrival}
Relacja Znaki Zodiaku o schemacie:
ZnakiZodiaku = {Id, Imię, Nazwisko, DzienUrodzenia, ZnakZodiaku}.
Mamy do czynienia z zależnością funkcyjną
DzieńUrodzenia -> ZnakZodiaku
czyli temu samemu dniu urodzenia odpowiada zawsze ten sam znak zodiaku.
Rysunek 7.3 Tabela pokazująca zależność znaku zodiaku od dnia urodzenia.
Tabela 7.8 Tabela pokazująca zależność znaku zodiaku od dnia urodzenia.
Id | Imie | Nazwisko | DzienUrodzenia | ZnakZodiaku |
---|---|---|---|---|
1 | Jan | Kowalski | 23 stycznia | Wodnik |
2 | Anna | Pawłowska | 1 kwietnia | Baran |
3 | Krzysztof | Tomaszewski | 23 kwietnia | Byk |
4 | Agata | Jaworska | 31 lipca | Lew |
5 | Hermenegilda | Kociubińska | 13 kwietnia | Baran |
6 | Apolinary | Paprocki | 5 września | Panna |
7 | Onufry | Zawacki | 13 kwietnia | Baran |
W rzeczywistości mamy tutaj do czynienia z czymś więcej, mianowicie z funkcją
f: DzieńUrodzenia -> ZnakZodiaku
przyporządkowującą dniu urodzenia znak zodiaku. Jednak ta funkcja nie daje się wyrazić za pomocą zależności funkcyjnej w sensie podanej powyżej definicji.
W procesie projektowania, dla każdego schematu relacji, identyfikujemy zbiór spełniających ją zależności funkcyjnych (zależny od konkretnego zastosowania). Na przykład dla relacji Loty identyfikujemy następujący zbiór zależności funkcyjnych między jej atrybutami:
{Flight} -> {From, To, Departure, Arrival}
{From, To, Departure} -> {Flight, Arrival}
{From, To, Arrival} -> {Flight, Departure}
Często jest stosowana skrócona forma zapisu polegająca na opuszczaniu przecinków i nawiasów klamrowych:
Flight -> From To Departure Arrival
From To Departure -> Flight Arrival
Nadkluczem relacji r o schemacie R = {A1, A2,..., An}
nazywamy każdy dowolny zbiór atrybutów
X z R
taki, że zachodzi zależność funkcyjna
X -> R
Inaczej mówiąc, wartość każdego atrybutu ma być jednoznacznie zdeterminowana przez wartości atrybutów zbioru X. Jednym z nadkluczy jest zawsze zbiór wszystkich atrybutów R.
Kluczem relacji r o schemacie R = {A1, A2,..., An}
nazywamy każdy minimalny nadklucz (nie zawierający w sobie żadnego innego nadklucza). Oznacza to, że zbiór atrybutów X jest kluczem, jeżeli wartość każdego atrybutu w R jest jednoznacznie zdeterminowana przez wartości atrybutów zbioru X i żaden podzbiór zbioru X nie ma już tej własności. Zawsze istnieje co najmniej jeden nadklucz - całe R, stąd wniosek, że istnieje co najmniej jeden minimalny nadklucz, czyli klucz. Jednak kluczy może być więcej, jak to pokazuje przykład relacji Loty. Zależności funkcyjne schematu Loty określają trzy klucze:
{Flight} {From, To, Departure} {From, To, Arrival}
Dla każdej relacji możemy arbitralnie wyróżnić jeden spośród kluczy. Wyróżniony klucz nazywa się kluczem głównym. Wchodzące w jego skład atrybuty są w zapisach schematów relacji podkreślane lub pogrubiane.
Dla relacji Loty wybieramy jako klucz główny atrybut Flight:
Loty = {Flight, From, To, Departure, Arrival}
Należy podkreślić fakt, że klucz główny to rola, arbitralnie narzucana podczas projektowania schematu relacji. Kluczy kandydujących do tej roli może być wiele, ale wybrany zostaje tylko jeden. Przy wyborze kierujemy się głównie wygodą użytkowania, o której w dużej mierze decyduje liczba atrybutów wchodzących w skład klucza (im mniej, tym lepiej), a także typ danych (preferowane typy liczb naturalnych).
Zależność od czegokolwiek innego niż klucz wprowadza wewnętrzną zależność między atrybutami tabeli. Powoduje możliwość determinowania wartości jednych atrybutów przez inne, czyli redundancję.
Pokazuje to tabelka, w której istnieje zależność X -> Y.
Rysunek 7.4 Schematyczne przedstawienie roli zależności funkcyjnych.
Jeśli X nie jest nadkluczem, to przedstawiona w tabelce sytuacja oznacza redundancję. Wartość w polu oznaczonym przez "?" jest już jednoznacznie zdeterminowana – musi to być y. Natomiast, gdy X jest nadkluczem, to przedstawiona sytuacja jest niemożliwa. Nie mogą istnieć dwa różne wiersze z tą samą wartością klucza.
Zależność funkcyjna X -> Y jest zależnością od klucza, jeśli zbiór atrybutów X jest nadkluczem.
Zależność funkcyjna X -> Y jest zależnością nie od klucza, jeśli:
Istnieją dwa typy zależności nie od klucza:
W schematach Dostawcy i Pracownicy występują zależności nie od klucza, odpowiednio:
Nazwa_dostawcy -> Adres_dostawcy (zależność częściowa)
Uczelnia -> Adres_uczelni (zależność przechodnia)
Poniżej przedstawiamy eliminację ze schematów relacji zależności „nie od klucza” dla przykładowych schematów.
Schemat dostawców
Dostawcy_towary {Nazwa_dostawcy, Nazwa_towaru, Adres_dostawcy, Cena}
dodajemy schemat
Dostawcy {Nazwa_dostawcy, Adres_dostawcy}
i usuwamy z oryginalnego schematu atrybut Adres_dostawcy, otrzymując schemat:
Towary {Nazwa_dostawcy, Towar, Cena}.
dodajemy schemat tabeli
Uczelnia {Uczelnia, Adres_uczelni}
i usuwamy z oryginalnego schematu atrybut Adres_uczelni, otrzymując schemat:
Pracownicy {Id_pracownika, Nazwisko, Uczelnia}.
Reasumując:
Metoda eliminowania „złych” zależności polega na wprowadzeniu dla zależności (częściowej lub przechodniej) osobnego schematu i usunięciu atrybutu stojącego po prawej stronie tej zależności z oryginalnego schematu.
Dostawcy = {Nazwa_dostawcy, Adres_dostawcy, Towar, Cena}.
Dostawcy = {Nazwa_dostawcy, Adres_dostawcy}
Towary = {Nazwa_dostawcy,Towar, Cena}.
W ten sposób zależności funkcyjne dyktują, jakie powinny być tabele w schemacie bazy danych. Najlepszym rozwiązaniem jest sytuacja, w której każda zależność funkcyjna określa pojedynczy schemat tabeli.
Relacja o schemacie R znajduje się w postaci normalnej Boyce'a-Codda, jeśli nie zawiera zależności nie od klucza, czyli dla każdej zależności
X -> A w schemacie relacji R (gdzie X podzbiór R, A atrybut w R) zachodzi
albo
albo
Jeśli schemat relacji znajduje się w postaci normalnej Boyce'a-Codda, nie można w tabeli przewidzieć jednych wartości w oparciu o inne, chociaż jak to będzie pokazane dalej, nie mamy gwarancji, że nie będzie innego rodzaju redundancji niż zależność funkcyjna.
Przykłady schematów w postaci normalnej Boyce'a-Codda:
F: Id_prac -> Nazwisko Funkcja Stanowisko
F: Flight -> From To Departure Arrival
F: From To Departure -> Flight Arrival
F: From To Arrival -> Flight Departure
Schemat niedający się sprowadzić do postaci normalnej Boyce’a-Codda
Nie każdy schemat tabeli da się sprowadzić do zbioru schematów tabel w postaci normalnej Boyce’a - Codda, bez utraty zawartych w tabelach informacji i z zachowaniem zależności funkcyjnych. Na przykład schematem takim jest
MUK = {Miasto, Ulica, Kod}
z zależnościami:
Miasto, Ulica -> Kod
Kod -> Miasto
Istnieją tutaj dwa klucze:
{Miasto, Ulica}
{Kod, Ulica}
Ze względu na zależność
Kod -> Miasto
schemat MUK nie jest w postaci normalnej Boyce'a-Codda. Tego schematu nie daje się rozłożyć z zachowaniem zależności funkcyjnych, ponieważ jedna z zależności funkcyjnych obejmuje wszystkie atrybuty.
Atrybut kluczowy jest to atrybut wchodzący w skład jednego z kluczy relacji (tabeli). Relacja o schemacie R znajduje się w trzeciej postaci normalnej, jeśli wszystkie zależności nie od klucza są między atrybutami kluczowymi, tj. dla każdej zależności X -> A w schemacie relacji R (gdzie X podzbiór R, A atrybut w R) zachodzi:
Albo
Albo
Albo
W trzeciej postaci normalnej wykluczony jest więc przypadek zależności:
X -> A
Gdzie:
Zatem takich zależności należy poszukiwać, w celu przekształcenia schematu relacji ze "złej" zależności na dwie relacje.
Przykład zależności funkcyjnej:
Kod -> Miasto
w schemacie MUK wskazuje, że schemat ten nie jest w postaci normalnej Boyce’a-Codda, ale jest w trzeciej postaci normalnej, bo atrybut Miasto jest atrybutem kluczowym – należy do jednego z kluczy:
{Miasto, Ulica}
Natomiast następujący schemat R, nie jest w trzeciej postaci normalnej.
R = {A,B,C,D}
F: AB -> C; B -> D; BC - >A
Kluczami są AB i BC. Istnieje zależność B -> D a D nie jest atrybutem kluczowym, B nie jest kluczem.
Czyli w powyższej relacji istnieje zależność częściowa, czyli relacja nie jest w trzeciej postaci normalnej (nie jest również w drugiej).
Dla „porządku nomenklatury” wypada jeszcze uporządkować pojęcie pierwszej i drugiej postaci normalnej. I tak:
Tabela jest w pierwszej postaci normalnej, jeśli nie dopuszcza istnienia wartości nieatomowych. Jej istnienie to jeden z postulatów Codd’a.
Schemat relacji jest w drugiej postaci normalnej, jeśli nie zawiera zależności funkcyjnych częściowych.
Brak "złych" zależności funkcyjnych nie gwarantuje jeszcze braku redundancji
i anomalii. Zilustrujemy jeszcze dwa rodzaje zależności:
Wielowartościowe oznaczające brak Czwartej
Postaci Normalnej
Złączeniowe oznaczające brak Piątej Postaci Normalnej
Ich istnienie implikuje redundancje i anomalie. Pominiemy dokładne definicje ograniczając się do przykładów.
Czwarta postać normalna
Schemat relacji znajduje się w czwartej postaci normalnej, jeśli nie zawiera zależności wielowartościowych.
Rysunek 7.5 Relacja zawierająca zależności wielowartościowe.
Przedstawiony schemat relacji jest w postaci normalnej Boyce’a-Codda, bo jedynym kluczem są wszystkie trzy atrybuty, a jednak w tabeli jest redundancja i możliwe są anomalie!
W relacji:
R = {Nr_stud, Przedmiot, Sport}
mamy do czynienia z tak zwanymi zależnościami wielowartościowymi:
Nr_stud ->> Przedmiot; Nr_stud ->> Sport
Powyższy schemat R nie jest zatem w czwartej postaci normalnej. Aby wyeliminować zależności wielowartościowe rozkładamy R na dwie relacje o schematach:
{Nr_stud, Przedmiot}
i
{Nr_stud, Sport}.
Zależność złączeniowa jest uogólnieniem zależności wielowartościowej w tym
sensie, że jej eliminacja polega na rozbiciu relacji na więcej niż dwie relacje.
Rozważmy zależności pomiędzy dostawcami, produktami i projektami, oraz
przyjmijmy następującą zasadę biznesową:
jeżeli
to
Trzeba podkreślić, że zdefiniowane powyżej reguły nie wynikają z żadnych innych przesłanek, niż nasza wiedza o zależnościach zachodzących w modelowanej rzeczywistości.
Rysunek 7.6 Relacja zawierająca zależności złączeniowe.
Przy tych zasadach zapis informacji w tabeli jest redundantny, bo jeżeli:
to redundantna jest już informacja, że:
Rozwiązaniem problemu jest podział relacji na trzy relacje:
Podział na tylko dwie relacje jest niewystarczający!
W relacjach (1) - (3) nie ma już redundancji, a ich złączenie daje wyjściową relację.
Sytuacja uległaby zmianie gdybyśmy chcieli przechowywać informację o ilości lub cenie zamówionych produktów dla danego projektu u konkretnego dostawcy. Wówczas rozbicie na trzy relacje nie byłoby możliwe.
Normalizacji nie doprowadza się czasem do końca, np:
Jeśli tak postępujemy, to musimy się liczyć ze wszystkimi konsekwencjami pozostawienia nieznormalizowanej tabeli i dlatego wszystkie zależności nie od klucza muszą być sprawdzane przy każdej modyfikacji bazy danych i wszystkie pozostające anomalie muszą mieć przygotowane specjalne traktowanie, np. przy użyciu dodatkowych tabel do obsługi anomalii wstawiania i usuwania i / lub procedur obsługujących anomalie.
Innym zagadnieniem baz o strukturze nieznormalizowanej, sa hurtownie danych, omawaine w oddzielnym wykładzie.