1/15Widok ogólny bazy danych – kompletny schemat biblioteczny

Od 1NF do 5NF – wszystkie tabele w jednym miejscu

Podsumowuje cały proces normalizacji systemu bibliotecznego.

W cyklu normalizacji przeszliśmy od jednej tabeli z 17 kolumnami do ośmiu czystych, wyspecjalizowanych tabel.

Ta prezentacja zbiera wszystkie tabele w jednym miejscu – pokazuje strukturę, klucze, relacje i zależności.

Widok = widok ogólny. Tu zobaczysz cały schemat bazy – od 1NF po 5NF – w jednym miejscu.
Slajd tytułowy – osiem tabel połączonych liniami, centralnie Czytelnicy

Prezentacja WidOK (Widok Ogólny) stanowi kompendium wiedzy o schemacie bazy danych systemu bibliotecznego. Znajdziesz tu wszystkie tabele powstałe w procesie normalizacji od 1NF do 5NF, wraz z ich kolumnami, kluczami i relacjami. To idealne miejsce do szybkiego przypomnienia sobie struktury bazy przed egzaminem lub przed przystąpieniem do implementacji.

W przeciwieństwie do pozostałych prezentacji z cyklu, które skupiają się na konkretnym etapie normalizacji, WidOK prezentuje całościowy obraz. Możesz go traktować jako mapę drogową po bazie danych – zobaczysz, które tabele są ze sobą połączone, jakie klucze obce łączą poszczególne encje i jak wygląda ostateczna struktura po przejściu wszystkich postaci normalnych.

Zachęcam do korzystania z tej prezentacji jako punktu odniesienia podczas pracy z pozostałymi materiałami. Jeśli w trakcie czytania którejś z poprzednich prezentacji zastanawiasz się, jak wygląda końcowy schemat – wróć tutaj. WidOK to Twoja ściągawka do całego cyklu normalizacji.

2/15Agenda – plan podróży przez 15 slajdów

Początki: jedna tabela. Koniec: osiem czystych tabel.

Prezentacja składa się z czterech części:

  • Część I: Ewolucja schematu (slajdy 3-8) – 1NF → 2NF → 3NF → BCNF → 4NF → 5NF
  • Część II: Relacje i klucze (slajdy 9-10) – FK, integralność referencyjna
  • Część III: Tabele szczegółowo (slajdy 11-14) – struktura każdej tabeli
  • Część IV: Podsumowanie (slajd 15) – schemat końcowy
Od chaosu do porządku – zobacz, jak zmieniała się struktura bazy na każdym etapie normalizacji.
Mapa prezentacji – cztery części połączone strzałkami

Agenda prezentacji WidOK została zaprojektowana tak, abyś mógł szybko znaleźć interesujące Cię informacje. Część I pokazuje ewolucję schematu – jak z jednej, chaotycznej tabeli powstawało osiem czystych, wyspecjalizowanych struktur. To kluczowa część, która pomaga zrozumieć, dlaczego normalizacja jest ważna i jak zmienia się projekt bazy na każdym etapie.

Część II koncentruje się na relacjach między tabelami – kluczach obcych, integralności referencyjnej i sposobach łączenia danych z różnych tabel. To praktyczna wiedza niezbędna do pisania zapytań JOIN. Część III przedstawia każdą tabelę z osobna, z pełną listą kolumn, typami danych i ograniczeniami. To z kolei przyda się przy tworzeniu zapytań INSERT i definiowaniu schematu w SQL.

Ostatnia część to podsumowanie całego cyklu normalizacji w formie jednego, kompletnego diagramu ERD. Możesz go wydrukować i mieć zawsze pod ręką podczas projektowania własnych baz danych. WidOK to nie tylko podsumowanie, ale przede wszystkim praktyczne narzędzie do nauki i codziennej pracy.

3/151NF: Początek – jedna tabela, 17 kolumn

Tabela Wypozyczenia w 1NF – wszystko w jednym miejscu

Stan po 1NF: jedna tabela, klucz główny ID_Wypozyczenia, trzy encje wymieszane.

-- Tabela: Wypozyczenia (1NF) – 17 kolumn
[Dane czytelnika]  Czytelnik, Adres, Miasto,
                        KodPocztowy, Telefon, Email
[Dane książki]      Tytul, Autor, ISBN, Gatunek,
                        RokWydania, Wydawnictwo
[Dane wypożyczenia] ID_Wypozyczenia(PK), DataWyp,
                        DataZwrotu, Kara, Status

Wszystkie dane wymieszane – czytelnicy, książki i wypożyczenia w jednej tabeli.

Stan początkowy: 17 kolumn, jedna tabela, trzy encje wymieszane. Tu zaczyna się normalizacja.
Tabela Wypozyczenia z 17 kolumnami pogrupowanymi kolorami

Stan po 1NF to baza danych w najprostszej możliwej formie. Pojedyncza tabela Wypozyczenia zawiera wszystkie informacje potrzebne do działania systemu bibliotecznego: dane osobowe czytelnika, metadane książki oraz informacje o konkretnym zdarzeniu wypożyczenia. Choć 1NF zapewnia atomowość komórek i istnienie klucza głównego, struktura ta jest daleka od optymalnej ze względu na wymieszanie trzech odrębnych encji.

W tabeli widać wyraźne pogrupowanie kolumn na trzy kategorie: sześć kolumn dotyczy czytelnika (od Czytelnik do Email), sześć kolumn dotyczy książki (od Tytul do Wydawnictwo), a cztery kolumny (plus klucz główny) dotyczą wypożyczenia. To wymieszanie jest źródłem redundancji – dane czytelnika powtarzają się przy każdym jego wypożyczeniu, a dane książki przy każdym wypożyczeniu tej książki.

Konsekwencje tej struktury to klasyczne anomalie: INSERT (nie można dodać czytelnika ani książki bez wypożyczenia), UPDATE (zmiana adresu wymaga modyfikacji wielu wierszy) i DELETE (usunięcie ostatniego wypożyczenia usuwa dane czytelnika i książki). Normalizacja do 2NF zaczyna rozwiązywać te problemy poprzez podział tabeli na trzy odrębne encje.

4/152NF: Trzy tabele – podział na encje

Eliminacja zależności częściowych – trzy tabele z FK

-- Tabela: Czytelnicy (2NF)
PK ID_Czytelnika | Imie, Nazwisko, Adres, Miasto,
    KodPocztowy, Telefon, Email

-- Tabela: Ksiazki (2NF)
PK ISBN | Tytul, Autor, Gatunek, RokWydania, Wydawnictwo

-- Tabela: Wypozyczenia (2NF)
PK ID_Wypozyczenia
FK ID_Czytelnika → Czytelnicy
FK ISBN          → Ksiazki
    DataWyp, DataZwrotu, Kara, Status

Każda encja ma swoją tabelę. Klucze obce łączą Wypozyczenia z czytelnikami i książkami.

2NF: z jednej tabeli → trzy. Czytelnicy, Ksiazki, Wypozyczenia – każda encja w osobnej tabeli.
Trzy tabele połączone strzałkami FK – Czytelnicy, Ksiazki, Wypozyczenia

Druga postać normalna przynosi fundamentalną zmianę w strukturze bazy danych. Z jednej, uniwersalnej tabeli Wypozyczenia powstają trzy wyspecjalizowane tabele, z których każda przechowuje dane jednej encji. Czytelnicy przechowują dane osobowe, Ksiazki przechowują metadane książek, a nowa tabela Wypozyczenia zawiera tylko informacje specyficzne dla zdarzenia wypożyczenia oraz klucze obce łączące ją z dwiema pozostałymi tabelami.

Kluczowym elementem nowej struktury są klucze obce. ID_Czytelnika w tabeli Wypozyczenia odwołuje się do klucza głównego tabeli Czytelnicy, a ISBN w tabeli Wypozyczenia odwołuje się do klucza głównego tabeli Ksiazki. Dzięki temu dane czytelnika i książki są przechowywane dokładnie raz, a w tabeli Wypozyczenia pojawia się jedynie identyfikator – bez powielania adresów, tytułów czy innych danych.

Efekt tej dekompozycji to natychmiastowa eliminacja anomalii INSERT, UPDATE i DELETE dla danych czytelnika i książki. Można dodać nowego czytelnika bez żadnego wypożyczenia, zmiana adresu wymaga modyfikacji jednego wiersza, a usunięcie wypożyczenia nie kasuje danych osobowych. To pierwszy krok w kierunku czystej, wydajnej struktury.

5/153NF: Cztery tabele – wyodrębnienie słownika Miasta

Eliminacja zależności przechodnich – pojawia się tabela Miasta

-- NOWA: Tabela Miasta (3NF)
PK ID_Miasta | Nazwa, KodPocztowy

-- Zmodyfikowana: Czytelnicy (3NF)
PK ID_Czytelnika | Imie, Nazwisko, Adres
FK ID_Miasta → Miasta | Telefon, Email

-- Bez zmian: Ksiazki (2NF/3NF)
PK ISBN | Tytul, Autor, Gatunek, RokWydania, Wydawnictwo

-- Bez zmian: Wypozyczenia (2NF/3NF)
PK ID_Wypozyczenia | FK ID_Czytelnika, ISBN
    DataWyp, DataZwrotu, Kara, Status

Usunięta zależność przechodnia: ID_Czytelnika → Miasto → KodPocztowy.

3NF: Miasta osobną tabelą. Kod pocztowy nie jest już powielany w każdym wierszu Czytelnicy.
Cztery tabele – Miasta połączona z Czytelnicy FK, reszta bez zmian

Trzecia postać normalna wprowadza subtelną, ale ważną zmianę: wyodrębnienie danych miasta i kodu pocztowego do osobnej tabeli słownikowej Miasta. W 2NF tabela Czytelnicy przechowywała bezpośrednio nazwę miasta i kod pocztowy. To powodowało zależność przechodnią: ID_Czytelnika → Miasto → KodPocztowy. Oznaczało to, że kod pocztowy zależał od miasta, które mogło się powtarzać dla wielu czytelników.

Nowa tabela Miasta pełni funkcję słownika – każda kombinacja (nazwa miasta, kod pocztowy) występuje dokładnie raz. W tabeli Czytelnicy zamiast nazwy miasta i kodu pocztowego pojawia się ID_Miasta jako klucz obcy. Dzięki temu zmiana kodu pocztowego dla miasta wymaga modyfikacji tylko jednego wiersza w tabeli Miasta, a nie wszystkich czytelników mieszkających w tym mieście.

Warto zwrócić uwagę, że tabele Ksiazki i Wypozyczenia nie ulegają zmianie w 3NF – ich struktura z 2NF była już zgodna z trzecią postacią normalną. To pokazuje, że nie każda tabela wymaga modyfikacji na każdym etapie normalizacji. Proces ten dotyczy tylko tych tabel, które wykazują konkretny typ zależności do wyeliminowania.

6/15BCNF: Sześć tabel – nakładające się klucze rozwiązane

Opiekunowie i Przypisania_BCNF – zamknięcie furtki 3NF

-- NOWE: Opiekunowie (BCNF)
PK ID_Czytelnika | ID_Bibliotekarza

-- NOWE: Przypisania_BCNF (BCNF)
PK (ID_Czytelnika, ISBN) | DataPrzypisania

-- Istniejące: Czytelnicy, Miasta, Ksiazki, Wypozyczenia

Rozwiązanie: zależność ID_Czyt → ID_Bib wyciągnięta do Opiekunowie.

3NF przepuszczała tę zależność przez 'furtkę'. BCNF zamyka furtkę.

BCNF: 6 tabel. Nakładające się klucze (ID_Czyt, ISBN) vs (ISBN, ID_Bib, Data) wymusiły podział.
Schemat BCNF – 6 tabel, Opiekunowie i Przypisania_BCNF zaznaczone

BCNF (Boyce-Codd Normal Form) to odpowiedź na ograniczenia 3NF w przypadku nakładających się kluczy kandydujących. W 3NF tabela Przypisania z kluczami (ID_Czytelnika, ISBN) i (ISBN, ID_Bibliotekarza, DataPrzypisania) spełniała warunki 3NF, ale wciąż wykazywała redundancję. Zależność ID_Czytelnika → ID_Bibliotekarza była przepuszczana przez 'furtkę' 3NF, ponieważ ID_Bibliotekarza jest atrybutem kluczowym (część drugiego klucza kandydującego).

Rozwiązanie BCNF polega na wyodrębnieniu tej zależności do osobnej tabeli Opiekunowie, gdzie ID_Czytelnika jest kluczem głównym, a ID_Bibliotekarza zwykłym atrybutem. W tabeli Przypisania_BCNF pozostaje tylko ID_Czytelnika (jako klucz obcy) wraz z ISBN i datą. Dzięki temu każdy czytelnik ma swój ID_Bibliotekarza przechowywany dokładnie raz, co eliminuje redundancję.

Warto podkreślić, że BCNF jest ostrzejszą wersją 3NF. Każda tabela w BCNF jest automatycznie w 3NF, ale nie odwrotnie. Różnica dotyczy tylko sytuacji z nakładającymi się kluczami kandydującymi, co w praktyce zdarza się stosunkowo rzadko. Większość tabel po 3NF jest już w BCNF – nasze tabele Czytelnicy, Miasta, Ksiazki i Wypozyczenia są w BCNF bez żadnych zmian.

7/154NF: Osiem tabel – niezależne listy rozdzielone

Eliminacja zależności wielowartościowych (MVD)

-- NOWE: Telefony (4NF) – MVD ID_Czyt →→ Telefon
FK ID_Czyt → Czytelnicy | Telefon, TypTel

-- NOWE: Emaile (4NF) – MVD ID_Czyt →→ Email
FK ID_Czyt → Czytelnicy | Email, TypEmail

-- Istniejące: Czytelnicy, Miasta, Ksiazki,
--            Wypozyczenia, Opiekunowie, Przypisania_BCNF

Każda niezależna lista (telefony, emaile) w osobnej tabeli. Brak produktu kartezjańskiego.

4NF: 8 tabel. Telefony i Emaile osobno – czytelnik może mieć wiele kontaktów każdego typu.
Czytelnicy połączeni z Telefony i Emaile – każda tabela osobno

Czwarta postać normalna rozwiązuje problem niezależnych list atrybutów – sytuacji, w której jeden czytelnik może mieć wiele numerów telefonów i wiele adresów email, a te listy są od siebie niezależne. W BCNF takie dane byłyby przechowywane w jednej tabeli, co prowadziłoby do efektu produktu kartezjańskiego: jeśli czytelnik ma 3 telefony i 2 emaile, w tabeli pojawiłoby się 6 wierszy (3 x 2).

Rozwiązaniem 4NF jest rozdzielenie każdej niezależnej listy do osobnej tabeli. Tabela Telefony przechowuje numery telefonów czytelnika (jeden wiersz na numer), a tabela Emaile przechowuje adresy email (jeden wiersz na adres). Dla czytelnika z 3 telefonami i 2 emailami będziemy mieć 3 wiersze w Telefony i 2 wiersze w Emaile - łącznie 5 wierszy zamiast 6, bez zbędnych kombinacji.

W nowej strukturze każda tabela zawiera również kolumnę TypTel/TypEmail, która określa rodzaj kontaktu (np. 'komórkowy', 'domowy', 'prywatny', 'służbowy'). To pozwala na elastyczne modelowanie danych kontaktowych bez utraty informacji. Klucz obcy ID_Czyt w obu tabelach łączy je z tabelą Czytelnicy, umożliwiając łatwe pobranie wszystkich kontaktów danego czytelnika.

8/155NF: Osiem tabel – finalny schemat

Po 5NF – wszystkie zależności złączeniowe (JD) wyeliminowane

-- FINALNY SCHEMAT – 8 tabel w 5NF
1. Czytelnicy       (ID_Czyt, Imie, Nazwisko, Adres, ID_Miasta,
                       Telefon, Email)
2. Miasta           (ID_Miasta, Nazwa, KodPocztowy)
3. Ksiazki          (ISBN, Tytul, Autor, Gatunek, RokWydania,
                       Wydawnictwo)
4. Wypozyczenia     (ID_Wyp, ID_Czyt, ISBN, DataWyp, DataZwrotu,
                       Kara, Status)
5. Opiekunowie      (ID_Czyt, ID_Bibliotekarza)
6. Przypisania_BCNF (ID_Czyt, ISBN, DataPrzypisania)
7. Telefony         (ID_Czyt, Telefon, TypTel)
8. Emaile           (ID_Czyt, Email, TypEmail)

Każda tabela w 5NF – żadnych JD niewynikających z kluczy kandydujących.

Schemat końcowy: 8 tabel, każda w 5NF. Koniec normalizacji relacyjnej.
Kompletny ERD – 8 tabel połączonych kluczami obcymi

Piąta postać normalna stanowi teoretyczne domknięcie procesu normalizacji relacyjnych baz danych. W praktyce 5NF rzadko wymaga zmian w schemacie, który jest już zgodny z 4NF. W naszym systemie bibliotecznym wszystkie osiem tabel po 4NF jest automatycznie w 5NF, ponieważ nie występują w nich zależności złączeniowe (JD) niewynikające z kluczy kandydujących.

Dla przypomnienia: zależność złączeniowa (JD) występuje, gdy relację można bezstratnie rozłożyć na trzy lub więcej projekcji. Typowym przykładem jest tabela (ISBN, Autor, ID_Bibliotekarza), gdzie każda para atrybutów jest niezależna. W naszym schemacie nie ma takiej sytuacji, ponieważ wszystkie relacje trójskładnikowe (jak Wypozyczenia łączące czytelnika, książkę i datę) mają dodatkowe atrybuty specyficzne dla całej trójki.

Osiem tabel w finalnym schemacie reprezentuje wszystkie encje i relacje w systemie bibliotecznym. Czytelnicy, Ksiazki i Miasta to tabele słownikowe przechowujące dane referencyjne. Wypozyczenia i Przypisania_BCNF to tabele zdarzeń. Opiekunowie, Telefony i Emaile to tabele atrybutów wielowartościowych. Każda z nich spełnia wszystkie wymagania 5NF, co gwarantuje brak anomalii przy operacjach INSERT, UPDATE i DELETE.

9/15Relacje między tabelami – mapa połączeń

Klucze obce łączą osiem tabel w spójną całość

Tabela źródłowaKlucz obcyTabela nadrzędnaTyp relacji
CzytelnicyID_MiastaMiastaN:1
WypozyczeniaID_CzytelnikaCzytelnicyN:1
WypozyczeniaISBNKsiazkiN:1
TelefonyID_CzytCzytelnicyN:1
EmaileID_CzytCzytelnicyN:1
OpiekunowieID_CzytelnikaCzytelnicy1:1
Przypisania_BCNFID_CzytelnikaCzytelnicyN:1
Przypisania_BCNFISBNKsiazkiN:1

W sumie: 8 relacji kluczy obcych łączących tabele. Czytelnicy to centralna tabela (6 połączeń).

Mapa relacji: Czytelnicy centralną tabelą – łączy się z 6 innymi tabelami. Ksiazki z 2.
Graf relacji – Czytelnicy w centrum, połączone z 6 tabelami

Mapa relacji między tabelami ukazuje architekturę całego systemu. Centralnym punktem jest tabela Czytelnicy, która łączy się z sześcioma innymi tabelami za pomocą kluczy obcych. To naturalne, ponieważ czytelnik jest kluczową encją w systemie bibliotecznym – to wokół niego koncentrują się wszystkie operacje: wypożyczenia, dane kontaktowe, opieka bibliotekarza i przypisania.

Druga pod względem liczby połączeń jest tabela Ksiazki, która łączy się z Wypozyczenia i Przypisania_BCNF. Miasta to słownik, który łączy się tylko z Czytelnikami. Wszystkie połączenia są typu jeden-do-wielu (N:1), z wyjątkiem Opiekunowie, które są jeden-do-jednego (1:1) – każdy czytelnik ma dokładnie jednego opiekuna-bibliotekarza.

Znajomość tych relacji jest kluczowa przy pisaniu zapytań SQL. Aby wyświetlić pełną informację o wypożyczeniu wraz z danymi czytelnika i książki, potrzebujemy JOIN łączący trzy tabele: Wypozyczenia JOIN Czytelnicy JOIN Ksiazki. Do pobrania kontaktów czytelnika potrzebujemy JOIN Czytelnicy LEFT JOIN Telefony LEFT JOIN Emaile. Każda relacja to potencjalny JOIN w zapytaniu.

10/15Integralność referencyjna – strażnik spójności

Jak klucze obce chronią dane?

Każdy klucz obcy w bazie wymusza regułę: wartość w kolumnie FK musi istnieć w tabeli nadrzędnej.

-- Próba dodania wypożyczenia dla nieistniejącego czytelnika
INSERT INTO Wypozyczenia
VALUES (100, 999, '978-83-123-4567-1', ...);
-- BŁĄD! Nie ma czytelnika z ID = 999 w tabeli Czytelnicy

-- Próba usunięcia czytelnika z wypożyczeniami
DELETE FROM Czytelnicy
WHERE ID_Czytelnika = 1;
-- BŁĄD! Istnieją wypożyczenia dla tego czytelnika (FK blokuje)

Reguły: ON DELETE RESTRICT, ON UPDATE CASCADE (często).

Integralność referencyjna = baza dba o spójność danych. Nie można odwołać się do nieistniejącego rekordu.
Schemat – strażnik z tarczą 'FK' blokujący nieprawidłowe operacje

Integralność referencyjna to mechanizm baz danych, który zapewnia, że relacje między tabelami są zawsze spójne. Gdy definiujemy klucz obcy, baza danych automatycznie sprawdza każdą operację INSERT, UPDATE i DELETE pod kątem naruszenia tej spójności. Nie można dodać wypożyczenia dla nieistniejącego czytelnika, ani usunąć czytelnika, który ma aktywne wypożyczenia.

W systemie bibliotecznym stosujemy następujące reguły integralności. Dla relacji Wypozyczenia → Czytelnicy oraz Wypozyczenia → Ksiazki używamy ON DELETE RESTRICT – nie pozwalamy usunąć czytelnika, który ma historię wypożyczeń. Dla relacji Telefony → Czytelnicy oraz Emaile → Czytelnicy używamy ON DELETE CASCADE – usunięcie czytelnika automatycznie usuwa jego dane kontaktowe. Dla Miasta → Czytelnicy używamy ON DELETE RESTRICT – nie można usunąć miasta, w którym mieszkają czytelnicy.

Dzięki integralności referencyjnej programiści nie muszą ręcznie sprawdzać spójności danych przy każdej operacji. Baza danych robi to automatycznie, co eliminuje całą klasę błędów związanych z osieroconymi rekordami (ang. orphan records). To jeden z najważniejszych powodów, dla których warto projektować bazę danych z prawidłowo zdefiniowanymi kluczami obcymi, a nie polegać wyłącznie na logice aplikacji.

11/15Szczegóły: Czytelnicy i Miasta

Tabela Czytelnicy – dane osobowe czytelników

KolumnaTypOgraniczeniaOpis
ID_CzytelnikaINTPK, AUTO_INCREMENTUnikalny identyfikator
ImieVARCHAR(50)NOT NULLImię czytelnika
NazwiskoVARCHAR(50)NOT NULLNazwisko czytelnika
AdresVARCHAR(100)Adres zamieszkania
ID_MiastaINTFK → MiastaIdentyfikator miasta
TelefonVARCHAR(20)Główny telefon
EmailVARCHAR(100)UNIQUEGłówny email (alternatywny klucz)

Tabela Miasta – słownik miast i kodów pocztowych

KolumnaTypOgraniczeniaOpis
ID_MiastaINTPK, AUTO_INCREMENTUnikalny identyfikator
NazwaVARCHAR(50)NOT NULLNazwa miejscowości
KodPocztowyVARCHAR(10)NOT NULLKod pocztowy

Zależność: ID_Miasta → {Nazwa, KodPocztowy} (każde ID miasta wyznacza nazwę i kod).

Czytelnicy: 7 kolumn + FK do Miasta. Email jest UNIQUE – alternatywny klucz kandydujący.
Czytelnicy i Miasta obok siebie ze strzałką FK między ID_Miasta

Tabela Czytelnicy to podstawowa encja systemu, przechowująca dane wszystkich osób korzystających z biblioteki. Każdy czytelnik ma unikalny identyfikator numeryczny (ID_Czytelnika) oraz unikalny adres email. Email ma założone ograniczenie UNIQUE, co oznacza, że może służyć jako alternatywny klucz naturalny do identyfikacji czytelnika – żadnych dwóch czytelników nie może mieć tego samego adresu email.

Tabela Miasta to słownik (tabela referencyjna), która przechowuje pary (nazwa miasta, kod pocztowy). Dzięki wyodrębnieniu tej tabeli w 3NF unikamy powtarzania nazw miast i kodów pocztowych w każdym wierszu Czytelnicy. Jeśli miasto zmieni kod pocztowy, wystarczy zaktualizować jeden wiersz w Miasta, a wszyscy czytelnicy automatycznie 'odziedziczą' nowy kod.

Warto zwrócić uwagę, że tabela Czytelnicy zawiera również kolumny Telefon i Email, które przechowują główne dane kontaktowe. Szczegółowe dane kontaktowe (wiele telefonów, wiele emaili) są przechowywane w osobnych tabelach Telefony i Emaile (zgodnie z 4NF). To rozwiązanie typu 'podstawowe dane w głównej tabeli, dodatkowe w osobnych' jest powszechnie stosowane w praktyce.

12/15Szczegóły: Ksiazki

Tabela Ksiazki – katalog biblioteczny

KolumnaTypOgraniczeniaOpis
ISBNVARCHAR(20)PKMiędzynarodowy numer książki
TytulVARCHAR(100)NOT NULLTytuł książki
AutorVARCHAR(50)NOT NULLAutor książki
GatunekVARCHAR(30)Gatunek literacki
RokWydaniaYEARRok wydania
WydawnictwoVARCHAR(50)Nazwa wydawnictwa

Klucz naturalny: ISBN – unikalny dla każdej książki na świecie.

Zależności: ISBN → Tytul, Autor, Gatunek, RokWydania, Wydawnictwo (pełna zależność od klucza).

Ksiazki: 6 kolumn. ISBN jako klucz naturalny – każda książka występuje dokładnie raz.
Tabela Ksiazki z przykładowymi danymi polskich klasyków literatury

Tabela Ksiazki stanowi katalog wszystkich książek dostępnych w bibliotece. Kluczem głównym jest ISBN (International Standard Book Number) – unikalny, międzynarodowy identyfikator książki. Użycie naturalnego klucza zamiast sztucznego ID ma tu sens, ponieważ ISBN jest globalnie unikalny, znany i używany w całym przemyśle wydawniczym. Nie ma ryzyka kolizji ani potrzeby tworzenia dodatkowego identyfikatora.

Kolumna Gatunek pozwala na kategoryzację książek według rodzaju literatury (np. powieść, poezja, dramat, literatura naukowa, poradnik). Kolumna RokWydania przechowuje rok publikacji, a Wydawnictwo nazwę wydawcy. Te trzy kolumny są opcjonalne – mogą pozostać puste, jeśli dane nie są dostępne. NULL w tych kolumnach oznacza 'brak danych', co jest lepszym rozwiązaniem niż wpisywanie wartości domyślnych, które mogłyby wprowadzać w błąd.

W tabeli Ksiazki zakładamy, że każda książka ma dokładnie jednego autora. W rzeczywistości wiele książek ma wielu autorów, co wymagałoby dodatkowej tabeli asocjacyjnej AutorzyKsiazek w bardziej złożonym modelu. Dla uproszczenia przykładu dydaktycznego przyjmujemy, że każda książka ma jednego głównego autora, co jest akceptowalnym uproszczeniem na potrzeby nauki normalizacji.

13/15Szczegóły: Wypozyczenia

Tabela Wypozyczenia – rejestr zdarzeń wypożyczeń

KolumnaTypOgraniczeniaOpis
ID_WypozyczeniaINTPK, AUTO_INCREMENTUnikalny identyfikator wypożyczenia
ID_CzytelnikaINTFK → CzytelnicyKto wypożyczył
ISBNVARCHAR(20)FK → KsiazkiCo wypożyczono
DataWypDATENOT NULLData wypożyczenia
DataZwrotuDATEData zwrotu (NULL = nie zwrócono)
KaraDECIMAL(5,2)DEFAULT 0Kara za opóźnienie
StatusVARCHAR(20)DEFAULT 'wypożyczona'Status: wypożyczona/zwrócona/przetrzymana

Klucz alternatywny: (ID_Czytelnika, ISBN, DataWyp) – ten sam czytelnik nie może wypożyczyć tej samej książki tego samego dnia.

Wypozyczenia: 7 kolumn. Łączy czytelnika z książką przez FK. DataZwrotu = NULL oznacza 'książka wciąż wypożyczona'.
Tabela Wypozyczenia z danymi – różne statusy i daty

Tabela Wypozyczenia to centralna tabela zdarzeń w systemie bibliotecznym. Każdy wiersz reprezentuje jedno zdarzenie wypożyczenia – konkretny fakt oddania książki czytelnikowi w określonym dniu. Kluczem głównym jest sztuczny identyfikator ID_Wypozyczenia, ale istnieje również naturalny klucz alternatywny: para (ID_Czytelnika, ISBN, DataWyp) – ten sam czytelnik nie może wypożyczyć tej samej książki dwa razy tego samego dnia.

Kolumna DataZwrotu przechowuje datę zwrotu książki. Wartość NULL w tej kolumnie oznacza, że książka nie została jeszcze zwrócona. To typowy wzorzec w systemach bibliotecznych – NULL jako 'w trakcie'. Kara jest naliczana automatycznie na podstawie daty zwrotu i regulaminu biblioteki, a Status przyjmuje wartości: 'wypozyczona' (książka w rękach czytelnika, jeszcze przed terminem), 'zwrocona' (książka oddana w terminie) lub 'przetrzymana' (książka oddana po terminie).

W tabeli obowiązuje ważne ograniczenie biznesowe: DataZwrotu >= DataWyp (książka nie może być zwrócona przed wypożyczeniem). To ograniczenie może być wymuszone przez constraint CHECK w SQL: CHECK (DataZwrotu IS NULL OR DataZwrotu >= DataWyp). Podobnie Status powinien być spójny z DataZwrotu – jeśli DataZwrotu IS NOT NULL i DataZwrotu <= termin, Status = 'zwrocona'; jeśli po terminie, Status = 'przetrzymana'.

14/15Szczegóły: Opiekunowie, Przypisania, Telefony, Emaile

Tabele pomocnicze – dane kontaktowe i opieka

Opiekunowie (BCNF)

KolumnaTypOgraniczeniaOpis
ID_CzytelnikaINTPK, FK → CzytelnicyKto ma opiekuna
ID_BibliotekarzaINTNOT NULLOpiekun (bibliotekarz)

Przypisania_BCNF (BCNF)

KolumnaTypOgraniczeniaOpis
ID_CzytelnikaINTFK → CzytelnicyKto przypisany
ISBNVARCHAR(20)FK → KsiazkiDo której książki
DataPrzypisaniaDATENOT NULLKiedy przypisano

Telefony (4NF)

KolumnaTypOgraniczenia
ID_CzytINTFK → Czytelnicy
TelefonVARCHAR(20)NOT NULL
TypTelVARCHAR(20)np. 'komórkowy', 'domowy'

Emaile (4NF)

KolumnaTypOgraniczenia
ID_CzytINTFK → Czytelnicy
EmailVARCHAR(100)NOT NULL
TypEmailVARCHAR(20)np. 'prywatny', 'służbowy'
Tabele BCNF i 4NF: każda przechowuje jeden rodzaj danych – brak redundancji, brak MVD.
Cztery tabele pomocnicze ze strzałkami FK do Czytelnicy i Ksiazki

Tabele pomocnicze powstałe w BCNF i 4NF pełnią kluczową rolę w modelowaniu specyficznych aspektów systemu bibliotecznego. Opiekunowie przechowują informację o tym, który bibliotekarz opiekuje się którym czytelnikiem. Jest to relacja 1:1 – każdy czytelnik ma dokładnie jednego opiekuna, ale jeden bibliotekarz może opiekować się wieloma czytelnikami. ID_Czytelnika jest kluczem głównym, co gwarantuje unikalność.

Przypisania_BCNF rejestrują, który bibliotekarz przypisał którą książkę któremu czytelnikowi i kiedy. Klucz złożony (ID_Czytelnika, ISBN) zapewnia, że czytelnik nie może mieć dwóch przypisań tej samej książki. DataPrzypisania jest dodatkowym atrybutem opisującym to zdarzenie. W przeciwieństwie do Opiekunowie, ta tabela nie przechowuje ID_Bibliotekarza – został on przeniesiony do Opiekunowie w ramach dekompozycji BCNF.

Telefony i Emaile to tabele powstałe w 4NF do przechowywania niezależnych list kontaktów. Każdy czytelnik może mieć wiele numerów telefonów (różnych typów) i wiele adresów email. Rozdzielenie tych list do osobnych tabel eliminuje problem produktu kartezjańskiego, który występowałby, gdyby wszystkie dane kontaktowe były w jednej tabeli. TypTel i TypEmail pozwalają na kategoryzację kontaktów.

15/15Podsumowanie – pełny schemat bazy bibliotecznej

Od 1 tabeli (17 kolumn) do 8 tabel (34 kolumny łącznie)

Końcowy schemat po przejściu wszystkich postaci normalnych:

-- SCHEMAT KONCOWY – 8 tabel w 5NF
1. Czytelnicy       (7 kolumn) – dane osobowe
2. Miasta           (3 kolumny) – słownik miast
3. Ksiazki          (6 kolumn) – katalog książek
4. Wypozyczenia     (7 kolumn) – zdarzenia wypożyczeń
5. Opiekunowie      (2 kolumny) – opiekunowie czytelników
6. Przypisania_BCNF (3 kolumny) – przypisania książek
7. Telefony         (3 kolumny) – numery telefonów
8. Emaile           (3 kolumny) – adresy email

-- Klucze obce: 8 relacji FK
-- Wszystkie tabele w 5NF
-- Brak anomalii INSERT, UPDATE, DELETE
-- Brak redundancji, brak MVD, brak JD

Gotowe do implementacji w MariaDB/MySQL.

Koniec normalizacji. Baza gotowa do wdrożenia. Każdy fakt przechowywany dokładnie raz.
Kompletny ERD – 8 tabel z kluczami i relacjami

Podsumowując cały proces normalizacji systemu bibliotecznego, przeszliśmy długą drogę od jednej, chaotycznej tabeli z 17 kolumnami do ośmiu czystych, wyspecjalizowanych tabel spełniających wszystkie wymagania piątej postaci normalnej. Każdy krok normalizacji eliminował konkretny typ problemu: 1NF zapewniła atomowość, 2NF usunęła zależności częściowe, 3NF wyeliminowała zależności przechodnie, BCNF zamknęła furtkę nakładających się kluczy, 4NF rozdzieliła niezależne listy, a 5NF potwierdziła brak zależności złączeniowych.

Efektem końcowym jest baza danych, w której każdy fakt jest przechowywany dokładnie raz, co eliminuje redundancję i ryzyko niespójności. Operacje INSERT, UPDATE i DELETE są bezpieczne i nie powodują utraty danych. Relacje między tabelami są jawnie zdefiniowane za pomocą kluczy obcych, a integralność referencyjna jest automatycznie egzekwowana przez system bazy danych.

Znajomość tego schematu jest kluczowa przed przystąpieniem do implementacji w SQL. Pamiętaj o kolejności tworzenia tabel: najpierw tabele nadrzędne (Miasta, Czytelnicy, Ksiazki), potem zależne (Wypozyczenia, Opiekunowie, Przypisania_BCNF, Telefony, Emaile). Przy usuwaniu tabel kolejność jest odwrotna. Powodzenia w implementacji!

Dane w formacie CSV: Pliki CSV z danymi dla każdej tabeli znajdują się w katalogu csv/. Aby zaimportować je do bazy, zaloguj się do MariaDB, wybierz bazę biblioteka i wykonaj: LOAD DATA LOCAL INFILE 'csv/miasta.csv' INTO TABLE Miasta FIELDS TERMINATED BY ';' LINES TERMINATED BY '\n' IGNORE 1 ROWS; (powtórz dla każdej tabeli w odpowiedniej kolejności).