Zestaw zadań: Proces normalizacji bazy danych krok po kroku

Zadanie 1: Analiza wymagań i projekt wstępnej, nienormalizowanej tabeli

Cel zadania

Zrozumienie procesu zbierania wymagań i przełożenie ich na jedną, płaską strukturę danych (formularz, arkusz kalkulacyjny), która stanowi punkt wyjścia do normalizacji. Identyfikacja powtarzających się grup danych.

Scenariusz

Jesteś deweloperem, który otrzymał zadanie stworzenia prototypu bazy danych dla dziekanatu małej uczelni. Obecnie wszystkie dane dotyczące zapisów studentów na przedmioty i uzyskanych ocen są przechowywane w jednym, ogromnym arkuszu kalkulacyjnym, który z każdym semestrem staje się coraz trudniejszy w zarządzaniu. Dziekanat dostarczył Ci przykładowy wydruk, który zawiera wszystkie niezbędne informacje: dane studenta, jego kierunek i wydział, a także listę przedmiotów, na które jest zapisany, wraz z informacjami o prowadzącym dany przedmiot, jego stopniu naukowym, a także oceną końcową i datą jej wystawienia. Twoim pierwszym zadaniem nie jest jeszcze tworzenie bazy, ale dokładna analiza tego "dokumentu". Musisz zidentyfikować wszystkie pojedyncze informacje (atrybuty) i zaprojektować strukturę jednej, wielkiej tabeli, która odzwierciedlałaby ten arkusz. Celem jest stworzenie cyfrowej wersji tego, co istnieje na papierze, aby na jej podstawie móc zademonstrować problemy wynikające z braku organizacji danych. Musisz zastanowić się, jak przedstawić fakt, że jeden student może uczęszczać na wiele kursów, a jeden wykładowca może prowadzić wiele przedmiotów. Twoja analiza ma być podstawą do dalszych prac i pierwszym krokiem w uświadomieniu pracownikom dziekanatu, dlaczego profesjonalna baza danych jest im absolutnie niezbędna do dalszego funkcjonowania i rozwoju.

Wykonanie krok po kroku

  1. Przeanalizuj dostarczone wymagania. Zidentyfikuj wszystkie kluczowe informacje (atrybuty), które muszą być przechowywane. Są to:
    • Dane studenta: numer albumu, imię, nazwisko, e-mail.
    • Dane kierunku: nazwa kierunku, nazwa wydziału, adres wydziału.
    • Dane o zapisie na przedmiot: kod przedmiotu, nazwa przedmiotu.
    • Dane wykładowcy: identyfikator wykładowcy, imię, nazwisko, stopień naukowy.
    • Dane o ocenie: ocena, data wystawienia.
  2. Zaprojektuj strukturę pojedynczej, płaskiej tabeli, która pomieści wszystkie te informacje. Zauważ, że dla jednego studenta będzie powtarzać się wiele informacji o kursach.
  3. Utwórz schemat tej tabeli (tzw. postać nienormalizowana - 0NF lub UNF). Zwróć uwagę na kolumny, które będą musiały przechowywać wiele wartości.
  4. Tabela: ARKUSZ_ZAPISOW_STUDENTA (0NF) +---------------+---------------+-------------------+----------------+----------------+----------------+----------------+------------------------------------+ | nr_albumu | imie_studenta | nazwisko_studenta | email_studenta | nazwa_kierunku | nazwa_wydzialu | adres_wydzialu | zapisy_na_przedmioty | +---------------+---------------+-------------------+----------------+----------------+----------------+----------------+------------------------------------+ | (klucz główny)| | | | | | | (atrybut wielowartościowy, złożony)| +---------------+---------------+-------------------+----------------+----------------+----------------+----------------+------------------------------------+
  5. Wewnątrz kolumny zapisy_na_przedmioty musiałyby znaleźć się wszystkie informacje o kursach, np. w formie tekstu: "KOD1, Nazwa1, ID_WYKŁ, Imie_Wykł, Nazwisko_Wykł, Stopień, Ocena, Data; KOD2, Nazwa2...".

Objaśnienia

Postać nienormalizowana (0NF) jest najprostszą, ale i najgorszą formą przechowywania danych. Charakteryzuje się tym, że w jednej komórce (jednym atrybucie) próbujemy przechowywać wiele wartości, często o złożonej strukturze. Taka organizacja jest nieefektywna, trudna w przeszukiwaniu i prowadzi do wielu problemów, zwanych anomaliami, które będziemy rozwiązywać w kolejnych krokach. Jest to jednak ważny punkt wyjścia, ponieważ odzwierciedla sposób, w jaki ludzie często organizują dane w prostych narzędziach, takich jak arkusze kalkulacyjne.

Wnioski

Zidentyfikowałeś wszystkie niezbędne atrybuty i stworzyłeś koncepcyjny model tabeli w postaci nienormalizowanej. Zrozumiałeś, na czym polega problem atrybutów wielowartościowych i grup powtarzających się, co stanowi idealny wstęp do wprowadzenia pierwszej postaci normalnej.

Zadanie 2: Implementacja tabeli w postaci nienormalizowanej i analiza problemów

Cel zadania

Praktyczne stworzenie w bazie danych tabeli w postaci nienormalizowanej oraz zasilenie jej danymi w celu namacalnego zademonstrowania problemów z redundancją i anomaliami (aktualizacji, wstawiania, usuwania).

Scenariusz

Po analizie teoretycznej nadszedł czas na praktykę. Twoim zadaniem jest stworzenie w systemie MariaDB nowej bazy danych o nazwie uczelnia_0nf i zaimplementowanie w niej zaprojektowanej wcześniej, nienormalizowanej tabeli. Aby uniknąć przechowywania wielu wartości w jednej komórce, co jest trudne w SQL, pójdziesz na pewien kompromis: dla każdego zapisu studenta na przedmiot stworzysz osobny wiersz, ale będziesz w nim powtarzać wszystkie dane studenta, kierunku i wydziału. Stworzysz więc jedną, bardzo szeroką tabelę o nazwie rejestr_ocen. Po zdefiniowaniu jej struktury, wstawisz do niej kilka przykładowych rekordów, które wyraźnie pokażą istniejące problemy. Na przykład, zapiszesz Jana Kowalskiego na trzy różne przedmioty, co spowoduje, że jego imię, nazwisko, email, kierunek i dane wydziału zostaną powtórzone trzy razy. Następnie, na podstawie tej tabeli, masz za zadanie przygotować dla dziekanatu krótką analizę. Musisz odpowiedzieć na pytania: co się stanie, jeśli Jan Kowalski zmieni adres e-mail? W ilu miejscach trzeba będzie dokonać zmiany? Co jeśli zechcemy dodać nowego studenta, który jeszcze nie zapisał się na żaden przedmiot? Czy będzie to możliwe? A co się stanie, gdy usuniemy ostatni wpis o studencie, który był zapisany tylko na jeden przedmiot? Czy stracimy o nim wszystkie informacje? Twoja demonstracja ma być ostatecznym dowodem na to, że obecna struktura jest nie do przyjęcia.

Wykonanie krok po kroku

  1. Stwórz nową bazę danych.
  2. CREATE DATABASE uczelnia_0nf CHARACTER SET utf8mb4 COLLATE utf8mb4_polish_ci;
  3. Przełącz się na nową bazę i stwórz jedną, denormalizowaną tabelę rejestr_ocen.
  4. USE uczelnia_0nf;
    CREATE TABLE rejestr_ocen (
        nr_albumu INT,
        imie_studenta VARCHAR(50),
        nazwisko_studenta VARCHAR(50),
        email_studenta VARCHAR(100),
        nazwa_kierunku VARCHAR(100),
        nazwa_wydzialu VARCHAR(100),
        adres_wydzialu VARCHAR(150),
        kod_przedmiotu VARCHAR(10),
        nazwa_przedmiotu VARCHAR(100),
        id_wykladowcy INT,
        imie_wykladowcy VARCHAR(50),
        nazwisko_wykladowcy VARCHAR(50),
        stopien_naukowy VARCHAR(50),
        ocena DECIMAL(2,1),
        data_wystawienia DATE
    );
  5. Wstaw kilka rekordów, które demonstrują redundancję danych.
  6. INSERT INTO rejestr_ocen VALUES
    (12345, 'Jan', 'Kowalski', 'j.kowalski@student.pl', 'Informatyka', 'Wydział Informatyki i Zarządzania', 'ul. Akademicka 1, Wrocław', 'INF01', 'Bazy Danych', 1, 'Adam', 'Nowak', 'dr hab.', 5.0, '2023-06-20'),
    (12345, 'Jan', 'Kowalski', 'j.kowalski@student.pl', 'Informatyka', 'Wydział Informatyki i Zarządzania', 'ul. Akademicka 1, Wrocław', 'INF02', 'Sieci Komputerowe', 2, 'Anna', 'Zielińska', 'prof. dr hab.', 4.5, '2023-06-22'),
    (54321, 'Anna', 'Nowakowska', 'a.nowakowska@student.pl', 'Informatyka', 'Wydział Informatyki i Zarządzania', 'ul. Akademicka 1, Wrocław', 'INF01', 'Bazy Danych', 1, 'Adam', 'Nowak', 'dr hab.', 4.0, '2023-06-20');
  7. Spójrz na poniższy fragment tabeli, aby zobaczyć redundancję w praktyce:
  8. +-----------+---------------+-------------------+-------------------------+----------------+--------------------+---------------------+ | nr_albumu | imie_studenta | nazwisko_studenta | email_studenta | kod_przedmiotu | nazwa_przedmiotu | nazwisko_wykladowcy | +-----------+---------------+-------------------+-------------------------+----------------+--------------------+---------------------+ | 12345 | Jan | Kowalski | j.kowalski@student.pl | INF01 | Bazy Danych | Nowak | | 12345 | Jan | Kowalski | j.kowalski@student.pl | INF02 | Sieci Komputerowe | Zielińska | | 54321 | Anna | Nowakowska | a.nowakowska@student.pl | INF01 | Bazy Danych | Nowak | +-----------+---------------+-------------------+-------------------------+----------------+--------------------+---------------------+ * Dane studenta Jana Kowalskiego (imię, nazwisko, email) są powtórzone dla każdego przedmiotu. * Dane przedmiotu "Bazy Danych" i jego wykładowcy są powtórzone dla każdego studenta.
  9. Przeanalizuj problemy (anomalie):
    • Anomalia aktualizacji: Aby zmienić e-mail Jana Kowalskiego, musisz zmodyfikować dwa wiersze. Jeśli zapomnisz o jednym, dane staną się niespójne.
    • -- Poprawna aktualizacja wymaga zmiany w wielu miejscach
      UPDATE rejestr_ocen SET email_studenta = 'jan.kowalski@nowy.pl' WHERE nr_albumu = 12345;
    • Anomalia wstawiania: Nie można dodać nowego studenta, dopóki nie zapisze się on na co najmniej jeden przedmiot, ponieważ nie ma miejsca na przechowywanie tylko danych studenta.
    • Anomalia usuwania: Gdyby Anna Nowakowska zrezygnowała z przedmiotu "Bazy Danych" i byłby to jej jedyny przedmiot, usunięcie tego rekordu spowodowałoby utratę wszystkich informacji o tej studentce.
    • -- Usunięcie tego wiersza kasuje wszystkie dane o Annie Nowakowskiej!
      DELETE FROM rejestr_ocen WHERE nr_albumu = 54321 AND kod_przedmiotu = 'INF01';

Wnioski

Praktycznie zademonstrowałeś, że przechowywanie wszystkich danych w jednej tabeli prowadzi do masowej redundancji i jest źródłem poważnych problemów (anomalii). Masz teraz solidne argumenty, aby rozpocząć proces normalizacji i uporządkować tę strukturę.

Zadanie 3: Identyfikacja atrybutów nieatomowych i transformacja do pierwszej postaci normalnej (1NF)

Cel zadania

Zrozumienie koncepcji atomowości atrybutów oraz przeprowadzenie pierwszego kroku normalizacji, czyli przekształcenia tabeli z postaci 0NF do pierwszej postaci normalnej (1NF) poprzez eliminację atrybutów wielowartościowych.

Scenariusz

Po udanej demonstracji problemów z jedną, wielką tabelą, dziekanat jest przekonany o konieczności zmian. Twój przełożony wyjaśnia Ci pierwszą, fundamentalną zasadę projektowania baz danych: zasadę atomowości. Mówi ona, że każda komórka w tabeli powinna zawierać tylko jedną, niepodzielną informację. Patrząc na pierwotny projekt z zadania 1, gdzie w jednej komórce miały znaleźć się dane o wszystkich kursach studenta, od razu widzisz naruszenie tej zasady. Twoim zadaniem jest teraz formalne zdefiniowanie, czym jest pierwsza postać normalna (1NF) i jak ją osiągnąć. Musisz wziąć pierwotną, nienormalizowaną strukturę i rozbić ją w taki sposób, aby każda komórka zawierała dokładnie jedną wartość. W praktyce oznacza to, że zamiast jednego wiersza dla studenta z listą kursów, stworzysz wiele wierszy dla tego samego studenta – po jednym dla każdego kursu, na który jest zapisany. To jest dokładnie to, co intuicyjnie zrobiłeś w zadaniu 2, tworząc tabelę rejestr_ocen. Teraz musisz jednak sformalizować ten proces. Musisz zdefiniować klucz główny dla tej nowej tabeli. Szybko orientujesz się, że sam numer albumu studenta nie wystarczy, bo się powtarza. Podobnie kod przedmiotu. Musisz więc stworzyć klucz złożony, który jednoznacznie zidentyfikuje każdy wiersz w tabeli.

Wykonanie krok po kroku

  1. Przeanalizuj tabelę rejestr_ocen z poprzedniego zadania. Potwierdź, że wszystkie jej atrybuty są atomowe (każda komórka przechowuje jedną wartość). Tabela ta już spełnia warunek atomowości.
  2. Zdefiniuj pierwszą postać normalną.
  3. Pierwsza postać normalna (1NF)

    Tabela znajduje się w pierwszej postaci normalnej (1NF), jeśli spełnia dwa podstawowe warunki:

    • Atomowość atrybutów: Każda komórka tabeli (na przecięciu wiersza i kolumny) musi zawierać pojedynczą, niepodzielną wartość. Nie może zawierać list, zbiorów ani innych złożonych struktur.
    • Unikalność wierszy: Każdy wiersz w tabeli musi być unikalny i możliwy do zidentyfikowania za pomocą klucza głównego (który może być prosty lub złożony).
  4. Zidentyfikuj odpowiedni klucz główny dla tabeli rejestr_ocen. Sam nr_albumu się powtarza. Sam kod_przedmiotu też może się powtórzyć (różni studenci na tym samym przedmiocie). Unikalną kombinacją, która identyfikuje konkretny zapis na kurs, jest para (nr_albumu, kod_przedmiotu).
  5. Stwórz nową bazę danych uczelnia_1nf i odtwórz w niej tabelę, tym razem definiując złożony klucz główny.
  6. CREATE DATABASE uczelnia_1nf CHARACTER SET utf8mb4 COLLATE utf8mb4_polish_ci;
    USE uczelnia_1nf;
    CREATE TABLE rejestr_ocen_1nf (
        nr_albumu INT,
        imie_studenta VARCHAR(50),
        nazwisko_studenta VARCHAR(50),
        email_studenta VARCHAR(100),
        nazwa_kierunku VARCHAR(100),
        nazwa_wydzialu VARCHAR(100),
        adres_wydzialu VARCHAR(150),
        kod_przedmiotu VARCHAR(10),
        nazwa_przedmiotu VARCHAR(100),
        id_wykladowcy INT,
        imie_wykladowcy VARCHAR(50),
        nazwisko_wykladowcy VARCHAR(50),
        stopien_naukowy VARCHAR(50),
        ocena DECIMAL(2,1),
        data_wystawienia DATE,
        PRIMARY KEY (nr_albumu, kod_przedmiotu)
    );
  7. Wstaw te same dane co poprzednio.
  8. INSERT INTO rejestr_ocen_1nf VALUES
    (12345, 'Jan', 'Kowalski', 'j.kowalski@student.pl', 'Informatyka', 'Wydział Informatyki i Zarządzania', 'ul. Akademicka 1, Wrocław', 'INF01', 'Bazy Danych', 1, 'Adam', 'Nowak', 'dr hab.', 5.0, '2023-06-20'),
    (12345, 'Jan', 'Kowalski', 'j.kowalski@student.pl', 'Informatyka', 'Wydział Informatyki i Zarządzania', 'ul. Akademicka 1, Wrocław', 'INF02', 'Sieci Komputerowe', 2, 'Anna', 'Zielińska', 'prof. dr hab.', 4.5, '2023-06-22'),
    (54321, 'Anna', 'Nowakowska', 'a.nowakowska@student.pl', 'Informatyka', 'Wydział Informatyki i Zarządzania', 'ul. Akademicka 1, Wrocław', 'INF01', 'Bazy Danych', 1, 'Adam', 'Nowak', 'dr hab.', 4.0, '2023-06-20');

Objaśnienia

Pierwsza postać normalna (1NF) to fundamentalny krok w projektowaniu relacyjnych baz danych. Wymusza ona usunięcie grup powtarzających się i atrybutów wielowartościowych. Osiąga się to poprzez "spłaszczenie" struktury, tak aby każdy wiersz i każda kolumna zawierały pojedynczą, atomową wartość. Kluczową częścią tego procesu jest zdefiniowanie klucza głównego, który jednoznacznie identyfikuje każdy wiersz. W przypadku, gdy żaden pojedynczy atrybut nie jest unikalny, musimy stworzyć klucz złożony (kompozytowy) z dwóch lub więcej atrybutów.

Wnioski

Przekształciłeś nienormalizowaną strukturę do pierwszej postaci normalnej. Tabela ma teraz atomowe wartości i zdefiniowany złożony klucz główny. Mimo to, wciąż obserwujesz te same anomalie co poprzednio (redundancja, problemy z aktualizacją, wstawianiem i usuwaniem), co dowodzi, że 1NF to dopiero początek drogi do dobrze zaprojektowanej bazy.

Zadanie 4: Analiza zależności funkcyjnych w tabeli 1NF

Cel zadania

Zrozumienie pojęcia zależności funkcyjnej, która jest teoretyczną podstawą do dalszej normalizacji. Nauczenie się, jak identyfikować pełne i częściowe zależności funkcyjne w tabeli posiadającej złożony klucz główny.

Scenariusz

Twój przełożony jest zadowolony z postępów, ale wskazuje, że kluczem do dalszej optymalizacji jest zrozumienie, jak dane są od siebie zależne. Wprowadza Cię w pojęcie "zależności funkcyjnej", tłumacząc, że jest to relacja między atrybutami, gdzie wartość jednego atrybutu (lub grupy atrybutów) determinuje wartość innego. Twoim zadaniem jest teraz wcielenie się w rolę analityka danych i dokładne zbadanie tabeli rejestr_ocen_1nf pod kątem tych zależności. Musisz wziąć na warsztat złożony klucz główny, czyli parę (nr_albumu, kod_przedmiotu), i przeanalizować wszystkie pozostałe atrybuty. Dla każdego z nich musisz odpowiedzieć na pytanie: czy jego wartość zależy od całego klucza złożonego, czy tylko od jego części? Na przykład, czy nazwisko_studenta zależy od tego, na jaki przedmiot się zapisał, czy wystarczy nam sam nr_albumu, aby je poznać? A jak jest z nazwa_przedmiotu? Czy zależy ona od studenta, czy tylko od kodu przedmiotu? Twoim zadaniem jest stworzenie formalnej listy wszystkich zidentyfikowanych zależności funkcyjnych i podzielenie ich na dwie grupy: te, które są "pełne" (zależą od całego klucza) i te, które są "częściowe" (zależą tylko od fragmentu klucza). Ta analiza jest absolutnie krytyczna, ponieważ to właśnie częściowe zależności są przyczyną anomalii w tabeli 1NF i to ich eliminacja jest celem drugiej postaci normalnej.

Wykonanie krok po kroku

  1. Przypomnij sobie strukturę tabeli rejestr_ocen_1nf i jej klucz główny: PRIMARY KEY (nr_albumu, kod_przedmiotu).
  2. Zdefiniuj zależność funkcyjną: Atrybut Y jest funkcyjnie zależny od atrybutu X (zapis X -> Y), jeśli dla każdej wartości X istnieje dokładnie jedna wartość Y.
  3. Przeanalizuj atrybuty zależne od części klucza - nr_albumu:
    • Czy znając nr_albumu, znamy imie_studenta? Tak.
    • Czy znając nr_albumu, znamy nazwisko_studenta? Tak.
    • ...i tak dalej dla email_studenta, nazwa_kierunku, nazwa_wydzialu, adres_wydzialu.

    Są to zależności częściowe, ponieważ te atrybuty zależą tylko od części klucza głównego.

    (nr_albumu) -> (imie_studenta, nazwisko_studenta, email_studenta, nazwa_kierunku, nazwa_wydzialu, adres_wydzialu)
  4. Przeanalizuj atrybuty zależne od części klucza - kod_przedmiotu:
    • Czy znając kod_przedmiotu, znamy nazwa_przedmiotu? Tak.
    • Czy znając kod_przedmiotu, znamy id_wykladowcy, imie_wykladowcy, nazwisko_wykladowcy, stopien_naukowy? Tak (zakładając, że jeden przedmiot prowadzi jeden wykładowca).

    To również są zależności częściowe.

    (kod_przedmiotu) -> (nazwa_przedmiotu, id_wykladowcy, imie_wykladowcy, nazwisko_wykladowcy, stopien_naukowy)
  5. Przeanalizuj atrybuty zależne od całego klucza:
    • Czy ocena zależy tylko od studenta? Nie. Czy tylko od przedmiotu? Nie. Zależy od konkretnego studenta i konkretnego przedmiotu.
    • Podobnie data_wystawienia.

    Są to zależności pełne.

    (nr_albumu, kod_przedmiotu) -> (ocena, data_wystawienia)

Objaśnienia

Analiza zależności funkcyjnych to formalny proces odkrywania reguł rządzących danymi. W kontekście normalizacji, kluczowe jest rozróżnienie między zależnościami częściowymi a pełnymi. Zależność częściowa występuje, gdy atrybut niekluczowy zależy tylko od fragmentu złożonego klucza głównego. To właśnie te zależności są bezpośrednią przyczyną redundancji i anomalii w tabeli 1NF. Na przykład, dane studenta powtarzają się w każdym wierszu jego zapisów, ponieważ zależą tylko od nr_albumu, a nie od całego klucza (nr_albumu, kod_przedmiotu).

Wnioski

Zidentyfikowałeś i sklasyfikowałeś wszystkie zależności funkcyjne w tabeli. Odkryłeś istnienie licznych zależności częściowych, które są źródłem problemów. Ta analiza jest mapą drogową do osiągnięcia drugiej postaci normalnej, która polega na wyeliminowaniu tych właśnie zależności.

Zadanie 5: Dekompozycja tabeli i osiągnięcie drugiej postaci normalnej (2NF)

Cel zadania

Praktyczne zastosowanie wiedzy o zależnościach częściowych do dekompozycji (podziału) tabeli 1NF na kilka mniejszych, połączonych relacjami tabel, które spełniają wymogi drugiej postaci normalnej (2NF).

Scenariusz

Twoja analiza zależności funkcyjnych okazała się strzałem w dziesiątkę. Teraz dokładnie wiesz, które dane są ze sobą powiązane i dlaczego w tabeli panuje bałagan. Nadszedł czas na wielkie porządki. Twoim zadaniem jest przeprowadzenie dekompozycji bezstratnej, czyli podziału jednej, wielkiej tabeli rejestr_ocen_1nf na kilka mniejszych, wyspecjalizowanych tabel. Każda zidentyfikowana w poprzednim kroku zależność częściowa ma stać się podstawą do stworzenia nowej tabeli. Musisz więc stworzyć osobną tabelę tylko na dane studentów, gdzie kluczem głównym będzie nr_albumu. Następnie, osobną tabelę na dane o przedmiotach i ich wykładowcach, gdzie kluczem głównym będzie kod_przedmiotu. Na końcu pozostanie tabela łącząca, która będzie przechowywać tylko te informacje, które zależą od obu kluczy – czyli oceny. Musisz starannie zaprojektować struktury tych nowych tabel, zdefiniować w nich klucze główne, a co najważniejsze, połączyć je ze sobą za pomocą kluczy obcych. Twoim celem jest stworzenie nowej struktury bazy danych, w której informacja o Janie Kowalskim będzie zapisana tylko w jednym miejscu, informacja o przedmiocie "Bazy Danych" również tylko w jednym miejscu, a anomalie, z którymi walczyłeś do tej pory, znikną.

Wykonanie krok po kroku

  1. Stwórz nową bazę danych uczelnia_2nf.
  2. CREATE DATABASE uczelnia_2nf CHARACTER SET utf8mb4 COLLATE utf8mb4_polish_ci;
    USE uczelnia_2nf;
  3. Na podstawie analizy zależności częściowych, wydziel tabelę Studenci.
  4. Tabela: Studenci +---------------+------------------+--------------------+-----------------------+--------------------+--------------------+--------------------+ | nr_albumu (PK)| imie_studenta | nazwisko_studenta | email_studenta | nazwa_kierunku | nazwa_wydzialu | adres_wydzialu | +---------------+------------------+--------------------+-----------------------+--------------------+--------------------+--------------------+
    CREATE TABLE Studenci (
        nr_albumu INT PRIMARY KEY,
        imie_studenta VARCHAR(50),
        nazwisko_studenta VARCHAR(50),
        email_studenta VARCHAR(100),
        nazwa_kierunku VARCHAR(100),
        nazwa_wydzialu VARCHAR(100),
        adres_wydzialu VARCHAR(150)
    );
  5. Wydziel tabelę Przedmioty.
  6. Tabela: Przedmioty +------------------+--------------------+----------------+--------------------+----------------------+-------------------+ | kod_przedmiotu(PK)| nazwa_przedmiotu | id_wykladowcy | imie_wykladowcy | nazwisko_wykladowcy | stopien_naukowy | +------------------+--------------------+----------------+--------------------+----------------------+-------------------+
    CREATE TABLE Przedmioty (
        kod_przedmiotu VARCHAR(10) PRIMARY KEY,
        nazwa_przedmiotu VARCHAR(100),
        id_wykladowcy INT,
        imie_wykladowcy VARCHAR(50),
        nazwisko_wykladowcy VARCHAR(50),
        stopien_naukowy VARCHAR(50)
    );
  7. Stwórz tabelę łączącą Oceny, która przechowa atrybuty w pełni zależne od klucza złożonego.
  8. Tabela: Oceny +-----------------+--------------------+----------------+---------------------+ | nr_albumu (FK) | kod_przedmiotu (FK)| ocena | data_wystawienia | +-----------------+--------------------+----------------+---------------------+ | PRIMARY KEY(nr_albumu, kod_przedmiotu) | +-----------------------------------------------------------------------------+
    CREATE TABLE Oceny (
        nr_albumu INT,
        kod_przedmiotu VARCHAR(10),
        ocena DECIMAL(2,1),
        data_wystawienia DATE,
        PRIMARY KEY (nr_albumu, kod_przedmiotu),
        FOREIGN KEY (nr_albumu) REFERENCES Studenci(nr_albumu),
        FOREIGN KEY (kod_przedmiotu) REFERENCES Przedmioty(kod_przedmiotu)
    );

Objaśnienia

Druga postać normalna (2NF)

Tabela znajduje się w drugiej postaci normalnej (2NF), jeśli spełnia następujące warunki:

  • Jest w pierwszej postaci normalnej (1NF).
  • Wszystkie jej atrybuty niekluczowe są w pełni funkcyjnie zależne od całego klucza głównego.

Oznacza to, że w tabeli ze złożonym kluczem głównym nie mogą istnieć żadne zależności częściowe, czyli sytuacje, w których atrybut niekluczowy zależy tylko od fragmentu klucza głównego.

Druga postać normalna (2NF) wymaga, aby tabela była w 1NF i aby wszystkie atrybuty niekluczowe były w pełni funkcyjnie zależne od całego klucza głównego. Oznacza to, że musimy wyeliminować wszystkie zależności częściowe. Robimy to poprzez dekompozycję: tworzymy nowe tabele dla każdej grupy atrybutów zależnych od tej samej części klucza. Oryginalna tabela zostaje zredukowana do tabeli łączącej (asocjacyjnej), która zawiera klucz złożony i tylko te atrybuty, które zależą od niego w całości. Klucze obce (FOREIGN KEY) zapewniają integralność referencyjną, czyli utrzymanie logicznych powiązań między nowo powstałymi tabelami.

Wnioski

Pomyślnie przekształciłeś bazę danych do drugiej postaci normalnej. Wyeliminowałeś zależności częściowe, co znacząco zredukowało redundancję danych. Zmiana e-maila studenta wymaga teraz modyfikacji tylko jednego rekordu w tabeli Studenci. Jednakże, w nowo powstałych tabelach mogą czaić się kolejne, bardziej subtelne problemy.

Zadanie 6: Zasilenie struktur 2NF danymi i weryfikacja eliminacji anomalii

Cel zadania

Migracja danych z tabeli 1NF do nowo utworzonych struktur 2NF. Praktyczna weryfikacja, czy anomalie aktualizacji, wstawiania i usuwania, które występowały wcześniej, zostały wyeliminowane.

Scenariusz

Nowa, lepsza struktura bazy danych jest już gotowa, ale na razie jest pusta. Twoim zadaniem jest teraz przeniesienie danych ze starej, wielkiej tabeli rejestr_ocen_1nf do trzech nowych, wyspecjalizowanych tabel: Studenci, Przedmioty i Oceny. Musisz napisać serię zapytań INSERT INTO ... SELECT, które w inteligentny sposób skopiują odpowiednie kolumny do nowych lokalizacji. Musisz przy tym uważać na duplikaty – na przykład dane Jana Kowalskiego powinny zostać wstawione do tabeli Studenci tylko raz, mimo że w tabeli źródłowej występowały wielokrotnie. Po pomyślnej migracji danych, musisz przeprowadzić serię testów, które udowodnią, że normalizacja do 2NF rozwiązała dotychczasowe problemy. Spróbujesz ponownie zmienić e-mail Jana Kowalskiego i sprawdzisz, czy wystarczy do tego modyfikacja jednego rekordu. Następnie dodasz nowego studenta, który nie jest jeszcze zapisany na żaden przedmiot, co wcześniej było niemożliwe. Na koniec, usuniesz jedyną ocenę Anny Nowakowskiej i zweryfikujesz, czy jej dane wciąż istnieją w tabeli Studenci, co potwierdzi, że nie tracisz już informacji o studentach przy usuwaniu ich zapisów na kursy. Twoje testy mają być ostatecznym dowodem na skuteczność przeprowadzonej normalizacji.

Wykonanie krok po kroku

  1. Zasil tabelę Studenci unikalnymi danymi studentów z tabeli rejestr_ocen_1nf. Użyj SELECT DISTINCT, aby uniknąć duplikatów.
  2. INSERT INTO uczelnia_2nf.Studenci (nr_albumu, imie_studenta, nazwisko_studenta, email_studenta, nazwa_kierunku, nazwa_wydzialu, adres_wydzialu)
    SELECT DISTINCT nr_albumu, imie_studenta, nazwisko_studenta, email_studenta, nazwa_kierunku, nazwa_wydzialu, adres_wydzialu
    FROM uczelnia_1nf.rejestr_ocen_1nf;
  3. Zasil tabelę Przedmioty unikalnymi danymi przedmiotów.
  4. INSERT INTO uczelnia_2nf.Przedmioty (kod_przedmiotu, nazwa_przedmiotu, id_wykladowcy, imie_wykladowcy, nazwisko_wykladowcy, stopien_naukowy)
    SELECT DISTINCT kod_przedmiotu, nazwa_przedmiotu, id_wykladowcy, imie_wykladowcy, nazwisko_wykladowcy, stopien_naukowy
    FROM uczelnia_1nf.rejestr_ocen_1nf;
  5. Zasil tabelę Oceny danymi o ocenach.
  6. INSERT INTO uczelnia_2nf.Oceny (nr_albumu, kod_przedmiotu, ocena, data_wystawienia)
    SELECT nr_albumu, kod_przedmiotu, ocena, data_wystawienia
    FROM uczelnia_1nf.rejestr_ocen_1nf;
  7. Sprawdź zawartość nowo utworzonych tabel. Redundancja została znacznie ograniczona.
  8. Tabela: Studenci +-----------+---------------+-------------------+-------------------------+-------------+ | nr_albumu | imie_studenta | nazwisko_studenta | email_studenta | nazwa_kie...| +-----------+---------------+-------------------+-------------------------+-------------+ | 12345 | Jan | Kowalski | j.kowalski@student.pl | Informatyka | | 54321 | Anna | Nowakowska | a.nowakowska@student.pl | Informatyka | +-----------+---------------+-------------------+-------------------------+-------------+ * Informacje o każdym studencie występują tylko raz.
    Tabela: Przedmioty +----------------+--------------------+---------------+---------------------+ | kod_przedmiotu | nazwa_przedmiotu | id_wykladowcy | nazwisko_wykladowcy | +----------------+--------------------+---------------+---------------------+ | INF01 | Bazy Danych | 1 | Nowak | | INF02 | Sieci Komputerowe | 2 | Zielińska | +----------------+--------------------+---------------+---------------------+ * Informacje o każdym przedmiocie występują tylko raz.
  9. Zweryfikuj rozwiązanie anomalii:
    • Aktualizacja: Zmień e-mail studenta. Wystarczy jedna operacja.
    • UPDATE uczelnia_2nf.Studenci SET email_studenta = 'jan.kowalski@nowy.pl' WHERE nr_albumu = 12345;
    • Wstawianie: Dodaj nowego studenta bez ocen.
    • INSERT INTO uczelnia_2nf.Studenci (nr_albumu, imie_studenta, nazwisko_studenta, email_studenta, nazwa_kierunku)
      VALUES (99999, 'Piotr', 'Nowicki', 'p.nowicki@student.pl', 'Socjologia');
    • Usuwanie: Usuń ocenę Anny Nowakowskiej. Jej dane pozostaną w tabeli Studenci.
    • DELETE FROM uczelnia_2nf.Oceny WHERE nr_albumu = 54321;
      -- Sprawdzenie: ten rekord wciąż istnieje
      SELECT * FROM uczelnia_2nf.Studenci WHERE nr_albumu = 54321;

Wnioski

Pomyślnie zmigrowałeś dane do struktury 2NF i udowodniłeś, że główne anomalie zostały wyeliminowane. Redundancja danych jest znacznie mniejsza, a operacje na danych są bezpieczniejsze i bardziej logiczne. Baza danych jest w znacznie lepszym stanie, ale wciąż może kryć w sobie pewne ukryte wady.

Zadanie 7: Identyfikacja zależności przechodnich w tabelach 2NF

Cel zadania

Zrozumienie koncepcji zależności przechodniej (transitive dependency), która jest przyczyną anomalii w niektórych tabelach 2NF, oraz nauczenie się, jak ją identyfikować.

Scenariusz

Jesteś dumny z osiągnięcia drugiej postaci normalnej. Baza danych wygląda o wiele czyściej, a podstawowe problemy zniknęły. Pokazujesz wyniki swojemu przełożonemu, który chwali Twoją pracę, ale od razu zwraca uwagę na kolejny, bardziej subtelny problem. Prosi Cię, abyś przyjrzał się tabeli Studenci. Wskazuje, że chociaż wszystkie atrybuty w tej tabeli zależą od klucza głównego, czyli nr_albumu, to niektóre z nich zależą od siebie nawzajem. Zadaje Ci pytanie: czy adres_wydzialu zależy bezpośrednio od studenta? A może jest tak, że student jest przypisany do kierunku, kierunek do wydziału, a dopiero wydział ma swój adres? To jest właśnie "zależność przechodnia". Twoim zadaniem jest ponowne wcielenie się w rolę analityka i zbadanie tabel Studenci oraz Przedmioty w poszukiwaniu takich ukrytych, pośrednich zależności. Musisz zidentyfikować atrybuty niekluczowe, które zamiast zależeć bezpośrednio od klucza głównego, zależą od innego atrybutu niekluczowego. Ta analiza jest niezbędna do osiągnięcia trzeciej postaci normalnej, która jest uważana za standard dla większości dobrze zaprojektowanych baz danych.

Wykonanie krok po kroku

  1. Przeanalizuj tabelę Studenci. Kluczem głównym jest nr_albumu.
  2. Tabela: Studenci (2NF) +---------------+------------------+--------------------+-----------------------+--------------------+--------------------+--------------------+ | nr_albumu (PK)| imie_studenta | nazwisko_studenta | email_studenta | nazwa_kierunku | nazwa_wydzialu | adres_wydzialu | +---------------+------------------+--------------------+-----------------------+--------------------+--------------------+--------------------+
  3. Zidentyfikuj zależności:
    • nr_albumu -> nazwa_kierunku (Student jest na jednym kierunku)
    • nazwa_kierunku -> nazwa_wydzialu (Kierunek należy do jednego wydziału)
    • nazwa_wydzialu -> adres_wydzialu (Wydział ma jeden adres)
  4. Zauważ, że istnieje łańcuch zależności: nr_albumu determinuje nazwa_kierunku, a nazwa_kierunku determinuje nazwa_wydzialu. Oznacza to, że nazwa_wydzialu zależy od klucza głównego nr_albumu w sposób przechodni (tranzytywny). To samo dotyczy adres_wydzialu.
  5. (nr_albumu) -> (nazwa_kierunku) -> (nazwa_wydzialu) -> (adres_wydzialu)
  6. Przeanalizuj tabelę Przedmioty. Kluczem głównym jest kod_przedmiotu.
  7. Tabela: Przedmioty (2NF) +------------------+--------------------+----------------+--------------------+----------------------+-------------------+ | kod_przedmiotu(PK)| nazwa_przedmiotu | id_wykladowcy | imie_wykladowcy | nazwisko_wykladowcy | stopien_naukowy | +------------------+--------------------+----------------+--------------------+----------------------+-------------------+
  8. Zidentyfikuj zależności:
    • kod_przedmiotu -> id_wykladowcy (Przedmiot jest prowadzony przez jednego wykładowcę)
    • id_wykladowcy -> imie_wykladowcy, nazwisko_wykladowcy, stopien_naukowy (ID wykładowcy jednoznacznie go identyfikuje)
  9. Tutaj również występuje zależność przechodnia. Dane wykładowcy (imię, nazwisko, stopień) zależą od klucza głównego kod_przedmiotu nie bezpośrednio, ale poprzez atrybut niekluczowy id_wykladowcy.
  10. (kod_przedmiotu) -> (id_wykladowcy) -> (imie_wykladowcy, nazwisko_wykladowcy, stopien_naukowy)

Objaśnienia

Zależność przechodnia (tranzytywna) występuje, gdy atrybut niekluczowy A zależy od atrybutu niekluczowego B, a atrybut B zależy od klucza głównego tabeli. Taka sytuacja wciąż prowadzi do anomalii. Na przykład, jeśli zmienimy nazwę wydziału, musimy to zrobić we wszystkich rekordach studentów z tego wydziału. Nie możemy też dodać nowego wydziału, dopóki nie przypiszemy do niego co najmniej jednego kierunku (i studenta). Trzecia postać normalna (3NF) ma na celu wyeliminowanie właśnie tych zależności.

Wnioski

Zidentyfikowałeś zależności przechodnie w obu głównych tabelach. Zrozumiałeś, że nawet po osiągnięciu 2NF baza danych może wciąż zawierać ukryte wady projektowe. Jesteś gotowy do ostatniego, kluczowego kroku normalizacji – osiągnięcia trzeciej postaci normalnej.

Zadanie 8: Dekompozycja tabel i osiągnięcie trzeciej postaci normalnej (3NF)

Cel zadania

Praktyczne wyeliminowanie zależności przechodnich poprzez dalszą dekompozycję tabel 2NF, co doprowadzi do uzyskania struktury bazy danych w trzeciej postaci normalnej (3NF).

Scenariusz

Uzbrojony w wiedzę o zależnościach przechodnich, przystępujesz do finalnego etapu projektowania schematu bazy danych. Twoim zadaniem jest teraz ostateczne "posprzątanie" struktury poprzez rozbicie tabel, w których zidentyfikowałeś te zależności. Musisz wziąć na warsztat tabelę Studenci i wydzielić z niej osobne byty: Wydziały i Kierunki. Stworzysz więc nową tabelę na wydziały, która będzie przechowywać tylko ich nazwy i adresy. Następnie tabelę na kierunki, która połączy kierunek z wydziałem za pomocą klucza obcego. W tabeli Studenci pozostanie już tylko odwołanie do kierunku, na którym studiuje dany student. Analogiczną operację musisz przeprowadzić dla tabeli Przedmioty. Wydzielisz z niej nową, niezależną tabelę Wykładowcy, która będzie zawierać wszystkie informacje o prowadzących. W tabeli Przedmioty pozostanie jedynie klucz obcy wskazujący na wykładowcę prowadzącego dany przedmiot. Po tej operacji każda tabela w Twojej bazie danych będzie opisywać tylko jeden, konkretny byt (studentów, wykładowców, przedmioty, wydziały), a wszystkie atrybuty niekluczowe będą zależeć tylko od klucza głównego, bezpośrednio i nieprzechodnio.

Wykonanie krok po kroku

  1. Stwórz nową bazę danych uczelnia_3nf.
  2. CREATE DATABASE uczelnia_3nf CHARACTER SET utf8mb4 COLLATE utf8mb4_polish_ci;
    USE uczelnia_3nf;
  3. Zacznij od dekompozycji tabeli Studenci z 2NF. Stwórz tabelę Wydzialy.
  4. Tabela: Wydzialy +-----------------+----------------------+------------------+ | id_wydzialu(PK) | nazwa_wydzialu | adres_wydzialu | +-----------------+----------------------+------------------+
    CREATE TABLE Wydzialy (
        id_wydzialu INT AUTO_INCREMENT PRIMARY KEY,
        nazwa_wydzialu VARCHAR(100) UNIQUE,
        adres_wydzialu VARCHAR(150)
    );
  5. Stwórz tabelę Kierunki, powiązaną z wydziałami.
  6. Tabela: Kierunki +-----------------+------------------+----------------+ | id_kierunku(PK) | nazwa_kierunku | id_wydzialu(FK)| +-----------------+------------------+----------------+
    CREATE TABLE Kierunki (
        id_kierunku INT AUTO_INCREMENT PRIMARY KEY,
        nazwa_kierunku VARCHAR(100) UNIQUE,
        id_wydzialu INT,
        FOREIGN KEY (id_wydzialu) REFERENCES Wydzialy(id_wydzialu)
    );
  7. Przeprojektuj tabelę Studenci, aby zawierała tylko dane o studentach i klucz obcy do kierunku.
  8. Tabela: Studenci +---------------+---------------+-------------------+----------------+----------------+ | nr_albumu(PK) | imie_studenta | nazwisko_studenta | email_studenta | id_kierunku(FK)| +---------------+---------------+-------------------+----------------+----------------+
    CREATE TABLE Studenci (
        nr_albumu INT PRIMARY KEY,
        imie_studenta VARCHAR(50),
        nazwisko_studenta VARCHAR(50),
        email_studenta VARCHAR(100),
        id_kierunku INT,
        FOREIGN KEY (id_kierunku) REFERENCES Kierunki(id_kierunku)
    );
  9. Teraz przeprowadź dekompozycję tabeli Przedmioty z 2NF. Stwórz tabelę Wykladowcy.
  10. Tabela: Wykladowcy +-----------------+-----------------+---------------------+-----------------+ | id_wykladowcy(PK) | imie_wykladowcy | nazwisko_wykladowcy | stopien_naukowy | +-----------------+-----------------+---------------------+-----------------+
    CREATE TABLE Wykladowcy (
        id_wykladowcy INT PRIMARY KEY,
        imie_wykladowcy VARCHAR(50),
        nazwisko_wykladowcy VARCHAR(50),
        stopien_naukowy VARCHAR(50)
    );
  11. Przeprojektuj tabelę Przedmioty.
  12. Tabela: Przedmioty +------------------+--------------------+-----------------+ | kod_przedmiotu(PK)| nazwa_przedmiotu | id_wykladowcy(FK) | +------------------+--------------------+-----------------+
    CREATE TABLE Przedmioty (
        kod_przedmiotu VARCHAR(10) PRIMARY KEY,
        nazwa_przedmiotu VARCHAR(100),
        id_wykladowcy INT,
        FOREIGN KEY (id_wykladowcy) REFERENCES Wykladowcy(id_wykladowcy)
    );
  13. Na koniec, przenieś bez zmian tabelę Oceny, dostosowując klucze obce do nowych tabel.
  14. CREATE TABLE Oceny (
        nr_albumu INT,
        kod_przedmiotu VARCHAR(10),
        ocena DECIMAL(2,1),
        data_wystawienia DATE,
        PRIMARY KEY (nr_albumu, kod_przedmiotu),
        FOREIGN KEY (nr_albumu) REFERENCES Studenci(nr_albumu),
        FOREIGN KEY (kod_przedmiotu) REFERENCES Przedmioty(kod_przedmiotu)
    );

Objaśnienia

Trzecia postać normalna (3NF)

Tabela znajduje się w trzeciej postaci normalnej (3NF), jeśli spełnia następujące warunki:

  • Jest w drugiej postaci normalnej (2NF).
  • Nie zawiera żadnych zależności przechodnich (tranzytywnych).

Oznacza to, że każdy atrybut niekluczowy musi zależeć bezpośrednio i wyłącznie od klucza głównego, a nie od innego atrybutu niekluczowego.

Trzecia postać normalna (3NF) wymaga, aby tabela była w 2NF i aby nie istniały w niej żadne zależności przechodnie. Oznacza to, że każdy atrybut niekluczowy musi zależeć bezpośrednio od klucza głównego, a nie od innego atrybutu niekluczowego. Osiągamy to poprzez wydzielenie grup atrybutów tworzących zależność przechodnią do osobnych tabel. W rezultacie otrzymujemy schemat bazy danych, który jest wysoce znormalizowany, elastyczny i odporny na większość typowych anomalii.

Wnioski

Zaprojektowałeś ostateczny, znormalizowany do 3NF schemat bazy danych. Składa się on z wielu małych, wyspecjalizowanych tabel, połączonych siecią relacji. Taka struktura minimalizuje redundancję, eliminuje anomalie i stanowi solidny fundament pod budowę aplikacji systemu dziekanatowego.

Zadanie 9: Migracja danych do finalnej struktury 3NF

Cel zadania

Zasilenie danymi w pełni znormalizowanej struktury 3NF, co wymaga wykonania wieloetapowej migracji z tabel 2NF i poprawnego uzupełnienia kluczy obcych.

Scenariusz

Stworzyłeś idealną, znormalizowaną strukturę, ale jest ona pusta. Twoim zadaniem jest teraz przeprowadzenie finalnej migracji danych ze schematu 2NF do schematu 3NF. To zadanie jest bardziej złożone niż poprzednie, ponieważ musisz wypełnić danymi kilka tabel w odpowiedniej kolejności, dbając o zachowanie relacji. Najpierw musisz wyodrębnić unikalne dane wydziałów i wstawić je do tabeli Wydzialy. Następnie, korzystając z nowo wygenerowanych identyfikatorów wydziałów, musisz wypełnić tabelę Kierunki. Podobnie postąpisz z wykładowcami – najpierw zasilisz tabelę Wykladowcy, a potem, używając ich ID, uzupełnisz tabelę Przedmioty. Dopiero mając przygotowane te tabele "słownikowe", będziesz mógł wypełnić główną tabelę Studenci, poprawnie przypisując każdego studenta do jego kierunku. Na samym końcu przeniesiesz dane do tabeli Oceny. Ten wieloetapowy proces migracji danych jest typowym zadaniem w projektach refaktoryzacji baz danych i wymaga starannego planowania oraz precyzyjnego wykonywania zapytań SQL.

Wykonanie krok po kroku

  1. Zasil tabelę Wydzialy unikalnymi danymi z tabeli uczelnia_2nf.Studenci.
  2. INSERT INTO uczelnia_3nf.Wydzialy (nazwa_wydzialu, adres_wydzialu)
    SELECT DISTINCT nazwa_wydzialu, adres_wydzialu FROM uczelnia_2nf.Studenci;
  3. Zasil tabelę Kierunki, łącząc dane z tabel uczelnia_2nf.Studenci i uczelnia_3nf.Wydzialy, aby pobrać id_wydzialu.
  4. INSERT INTO uczelnia_3nf.Kierunki (nazwa_kierunku, id_wydzialu)
    SELECT DISTINCT s.nazwa_kierunku, w.id_wydzialu
    FROM uczelnia_2nf.Studenci s
    JOIN uczelnia_3nf.Wydzialy w ON s.nazwa_wydzialu = w.nazwa_wydzialu;
  5. Zasil tabelę Wykladowcy.
  6. INSERT INTO uczelnia_3nf.Wykladowcy (id_wykladowcy, imie_wykladowcy, nazwisko_wykladowcy, stopien_naukowy)
    SELECT DISTINCT id_wykladowcy, imie_wykladowcy, nazwisko_wykladowcy, stopien_naukowy FROM uczelnia_2nf.Przedmioty;
  7. Zasil tabelę Przedmioty.
  8. INSERT INTO uczelnia_3nf.Przedmioty (kod_przedmiotu, nazwa_przedmiotu, id_wykladowcy)
    SELECT DISTINCT kod_przedmiotu, nazwa_przedmiotu, id_wykladowcy FROM uczelnia_2nf.Przedmioty;
  9. Zasil główną tabelę Studenci.
  10. INSERT INTO uczelnia_3nf.Studenci (nr_albumu, imie_studenta, nazwisko_studenta, email_studenta, id_kierunku)
    SELECT DISTINCT s.nr_albumu, s.imie_studenta, s.nazwisko_studenta, s.email_studenta, k.id_kierunku
    FROM uczelnia_2nf.Studenci s
    JOIN uczelnia_3nf.Kierunki k ON s.nazwa_kierunku = k.nazwa_kierunku;
  11. Na koniec zasil tabelę Oceny.
  12. INSERT INTO uczelnia_3nf.Oceny (nr_albumu, kod_przedmiotu, ocena, data_wystawienia)
    SELECT nr_albumu, kod_przedmiotu, ocena, data_wystawienia FROM uczelnia_2nf.Oceny;

Wnioski

Przeprowadziłeś skomplikowaną, wieloetapową migrację danych do w pełni znormalizowanej struktury. Zrozumiałeś, jak ważna jest kolejność operacji i jak używać złączeń do uzupełniania kluczy obcych. Baza danych jest teraz nie tylko dobrze zaprojektowana, ale również wypełniona spójnymi danymi.

Zadanie 10: Weryfikacja 3NF i odtwarzanie widoków za pomocą złączeń

Cel zadania

Potwierdzenie, że proces normalizacji był bezstratny. Nauczenie się, jak za pomocą zapytań JOIN odtworzyć pierwotny, płaski widok danych z nowej, znormalizowanej struktury składającej się z wielu tabel.

Scenariusz

Proces normalizacji został zakończony. Dziekan jest pod wrażeniem nowej, eleganckiej struktury, ale ma jedną, kluczową obawę: czy w trakcie tego całego podziału na małe tabelki nie utracono jakichś informacji? Czy nadal będzie mógł uzyskać raport, który wygląda dokładnie tak, jak jego stary, wielki arkusz kalkulacyjny, zawierający wszystkie informacje w jednym wierszu? Twoim zadaniem jest rozwianie tych wątpliwości. Musisz napisać jedno, duże zapytanie SQL, które połączy ze sobą wszystkie nowo utworzone tabele (Studenci, Kierunki, Wydzialy, Oceny, Przedmioty, Wykladowcy) i odtworzy pierwotny, denormalizowany widok danych. Wynik Twojego zapytania ma mieć dokładnie te same kolumny i wiersze, co tabela rejestr_ocen z samego początku Twojej pracy. Pomyślne wykonanie tego zadania będzie ostatecznym dowodem na to, że normalizacja jest procesem bezstratnej dekompozycji – porządkuje dane i eliminuje redundancję, ale nie usuwa żadnych informacji ani możliwości ich powiązania.

Wykonanie krok po kroku

  1. Przeanalizuj schemat bazy uczelnia_3nf i zaplanuj, w jakiej kolejności połączysz tabele.
  2. Napisz zapytanie, które połączy wszystkie 6 tabel.
  3. SELECT
        s.nr_albumu,
        s.imie_studenta,
        s.nazwisko_studenta,
        s.email_studenta,
        k.nazwa_kierunku,
        w.nazwa_wydzialu,
        w.adres_wydzialu,
        p.kod_przedmiotu,
        p.nazwa_przedmiotu,
        wy.id_wykladowcy,
        wy.imie_wykladowcy,
        wy.nazwisko_wykladowcy,
        wy.stopien_naukowy,
        o.ocena,
        o.data_wystawienia
    FROM
        Studenci s
    JOIN Kierunki k ON s.id_kierunku = k.id_kierunku
    JOIN Wydzialy w ON k.id_wydzialu = w.id_wydzialu
    JOIN Oceny o ON s.nr_albumu = o.nr_albumu
    JOIN Przedmioty p ON o.kod_przedmiotu = p.kod_przedmiotu
    JOIN Wykladowcy wy ON p.id_wykladowcy = wy.id_wykladowcy
    ORDER BY s.nr_albumu, p.kod_przedmiotu;
  4. Porównaj wynik tego zapytania z zawartością tabeli uczelnia_0nf.rejestr_ocen. Powinien być identyczny.

Objaśnienia

Kluczową cechą dobrze przeprowadzonej normalizacji jest jej bezstratność. Oznacza to, że w dowolnym momencie możemy odtworzyć dowolny widok danych, który był możliwy do uzyskania przed normalizacją. Robimy to za pomocą złączeń (JOIN), które "składają" dane z powrotem w jedną całość na podstawie zdefiniowanych relacji (kluczy obcych). Chociaż dane są fizycznie przechowywane w wielu miejscach w sposób zoptymalizowany, logicznie wciąż stanowią spójną całość.

Wnioski

Udowodniłeś, że proces normalizacji jest w pełni odwracalny na poziomie zapytań. Potrafisz efektywnie pobierać i łączyć dane ze złożonej, znormalizowanej struktury, aby dostarczyć użytkownikowi końcowemu informacje w dowolnej, pożądanej przez niego formie. Cały proces projektowania bazy danych został zakończony sukcesem.

Zadanie 11: Tworzenie widoków dla uproszczenia zapytań

Cel zadania

Nauczenie się tworzenia i wykorzystywania widoków (VIEW) w celu uproszczenia skomplikowanych zapytań, ukrycia złożoności schematu bazy danych przed użytkownikami końcowymi i zapewnienia spójnego dostępu do danych.

Scenariusz

Zapytanie, które napisałeś w poprzednim zadaniu, działa doskonale, ale jest bardzo długie i skomplikowane. Pracownicy dziekanatu, którzy mają podstawową znajomość SQL, byliby przerażeni, gdyby musieli pisać je za każdym razem, gdy potrzebują pełnego raportu. Twój przełożony sugeruje rozwiązanie: stworzenie "wirtualnej tabeli", znanej jako widok. Twoim zadaniem jest zapisanie skomplikowanego zapytania łączącego wszystkie tabele jako widok o nazwie Pelny_Rejestr_Ocen. Po stworzeniu widoku, każdy użytkownik bazy danych będzie mógł odpytać go tak, jakby to była zwykła, pojedyncza tabela, nie martwiąc się o skomplikowane złączenia. Musisz najpierw stworzyć widok, a następnie zademonstrować, jak proste staje się teraz pobieranie danych. Na przykład, pokażesz, jak za pomocą prostego zapytania SELECT * FROM Pelny_Rejestr_Ocen WHERE nazwisko_studenta = 'Kowalski'; można uzyskać wszystkie potrzebne informacje, bez pisania ani jednego JOIN-a. To rozwiązanie znacznie ułatwi pracę mniej zaawansowanym użytkownikom i zmniejszy ryzyko popełnienia przez nich błędu.

Wykonanie krok po kroku

  1. Użyj polecenia CREATE VIEW, aby zapisać zapytanie z poprzedniego zadania jako widok.
  2. CREATE VIEW Pelny_Rejestr_Ocen AS
    SELECT
        s.nr_albumu,
        s.imie_studenta,
        s.nazwisko_studenta,
        s.email_studenta,
        k.nazwa_kierunku,
        w.nazwa_wydzialu,
        w.adres_wydzialu,
        p.kod_przedmiotu,
        p.nazwa_przedmiotu,
        wy.id_wykladowcy,
        wy.imie_wykladowcy,
        wy.nazwisko_wykladowcy,
        wy.stopien_naukowy,
        o.ocena,
        o.data_wystawienia
    FROM
        Studenci s
    JOIN Kierunki k ON s.id_kierunku = k.id_kierunku
    JOIN Wydzialy w ON k.id_wydzialu = w.id_wydzialu
    JOIN Oceny o ON s.nr_albumu = o.nr_albumu
    JOIN Przedmioty p ON o.kod_przedmiotu = p.kod_przedmiotu
    JOIN Wykladowcy wy ON p.id_wykladowcy = wy.id_wykladowcy;
  3. Teraz odpytaj widok tak, jakby był zwykłą tabelą.
  4. SELECT * FROM Pelny_Rejestr_Ocen;
  5. Zademonstruj prostotę filtrowania danych za pomocą widoku.
  6. SELECT imie_studenta, nazwisko_studenta, nazwa_przedmiotu, ocena
    FROM Pelny_Rejestr_Ocen
    WHERE nazwisko_wykladowcy = 'Nowak';

Objaśnienia

Widok (VIEW) nie przechowuje fizycznie danych. Jest to zapisane w bazie danych zapytanie SELECT, które jest wykonywane za każdym razem, gdy odwołujemy się do widoku. Widoki są potężnym narzędziem do upraszczania dostępu do danych, zapewniania bezpieczeństwa (można dać użytkownikowi dostęp tylko do widoku, a nie do tabel źródłowych) oraz do zachowania wstecznej kompatybilności, gdy zmienia się struktura tabel bazowych.

Wnioski

Nauczyłeś się tworzyć i używać widoków, aby uprościć pracę ze złożonym, znormalizowanym schematem bazy danych. Potrafisz teraz dostarczać dane użytkownikom w prostej i przystępnej formie, jednocześnie zachowując wszystkie zalety wynikające z normalizacji.

Zadanie 12: Refaktoryzacja i dodanie kluczy głównych z autoinkrementacją

Cel zadania

Ulepszenie istniejącego schematu 3NF poprzez zastąpienie kluczy głównych opartych na danych biznesowych (jak kod_przedmiotu) kluczami sztucznymi (surogatowymi) z mechanizmem AUTO_INCREMENT, co zwiększa elastyczność i wydajność bazy danych.

Scenariusz

System działa dobrze, ale pojawia się nowy problem. Władze uczelni postanowiły zmienić system kodowania przedmiotów. Stary kod 'INF01' ma zostać zastąpiony nowym 'CS101'. Z przerażeniem odkrywasz, że kod_przedmiotu jest kluczem głównym w tabeli Przedmioty i kluczem obcym w tabeli Oceny. Jego zmiana wymagałaby kaskadowej aktualizacji w wielu miejscach i jest operacją ryzykowną. Twój mentor wyjaśnia, że używanie "naturalnych" kluczy, czyli danych, które mają znaczenie biznesowe (jak kod kursu, numer PESEL, NIP), jako kluczy głównych jest często złą praktyką, właśnie z powodu ich potencjalnej zmienności. Proponuje refaktoryzację schematu. Twoim zadaniem jest zmodyfikowanie tabel Przedmioty i Wykladowcy (oraz opcjonalnie innych), aby ich kluczem głównym stała się nowa, techniczna kolumna, np. id_przedmiotu, typu INT z atrybutem AUTO_INCREMENT. Dawny klucz naturalny, kod_przedmiotu, pozostanie w tabeli jako zwykła, unikalna kolumna. Musisz przeprowadzić tę zmianę, dostosować klucze obce w tabelach zależnych i zrozumieć, dlaczego takie podejście, zwane używaniem kluczy surogatowych, jest w większości przypadków preferowane.

Wykonanie krok po kroku

  1. Stwórz nową bazę danych uczelnia_3nf_final, aby przeprowadzić refaktoryzację.
  2. CREATE DATABASE uczelnia_3nf_final CHARACTER SET utf8mb4 COLLATE utf8mb4_polish_ci;
    USE uczelnia_3nf_final;
  3. Skopiuj tabele Wydzialy i Kierunki, które już używają kluczy surogatowych.
  4. Przeprojektuj tabelę Wykladowcy, zmieniając klucz główny.
  5. -- Stara wersja używała id_wykladowcy, które musieliśmy podawać ręcznie
    -- Nowa wersja z AUTO_INCREMENT
    CREATE TABLE Wykladowcy (
        id_wykladowcy INT AUTO_INCREMENT PRIMARY KEY,
        -- Można dodać stary identyfikator jako zwykłe pole, jeśli jest potrzebny
        -- stary_id_wykladowcy INT UNIQUE, 
        imie_wykladowcy VARCHAR(50),
        nazwisko_wykladowcy VARCHAR(50),
        stopien_naukowy VARCHAR(50)
    );
  6. Przeprojektuj tabelę Przedmioty, dodając nowy klucz główny i zachowując stary jako unikalny identyfikator biznesowy.
  7. CREATE TABLE Przedmioty (
        id_przedmiotu INT AUTO_INCREMENT PRIMARY KEY,
        kod_przedmiotu VARCHAR(10) UNIQUE NOT NULL,
        nazwa_przedmiotu VARCHAR(100),
        id_wykladowcy INT,
        FOREIGN KEY (id_wykladowcy) REFERENCES Wykladowcy(id_wykladowcy)
    );
  8. Dostosuj tabelę Oceny, aby używała nowego klucza obcego id_przedmiotu.
  9. -- Kopiujemy strukturę tabel Studenci
    CREATE TABLE Studenci LIKE uczelnia_3nf.Studenci;
    -- ...i Kierunki, Wydzialy...
    -- A teraz Oceny
    CREATE TABLE Oceny (
        id_oceny INT AUTO_INCREMENT PRIMARY KEY, -- Dodanie klucza głównego do tabeli Oceny
        nr_albumu INT,
        id_przedmiotu INT,
        ocena DECIMAL(2,1),
        data_wystawienia DATE,
        FOREIGN KEY (nr_albumu) REFERENCES Studenci(nr_albumu),
        FOREIGN KEY (id_przedmiotu) REFERENCES Przedmioty(id_przedmiotu),
        UNIQUE (nr_albumu, id_przedmiotu) -- Zapewnienie, że student ma jedną ocenę z przedmiotu
    );

Objaśnienia

Klucz surogatowy (sztuczny) to klucz główny, który nie ma żadnego znaczenia biznesowego – jest to zazwyczaj liczba całkowita, której wartość jest automatycznie nadawana przez system bazy danych (AUTO_INCREMENT). Jego główną zaletą jest stabilność. Ponieważ nie jest on powiązany z żadną rzeczywistą cechą opisywanego obiektu, nigdy nie będzie potrzeby jego zmiany. Upraszcza to zarządzanie relacjami i operacje aktualizacji. Klucz naturalny (np. kod_przedmiotu) wciąż pozostaje w tabeli, ale jako zwykły atrybut z ograniczeniem UNIQUE, aby zapewnić unikalność na poziomie biznesowym.

Wnioski

Ulepszyłeś swój schemat bazy danych, wprowadzając klucze surogatowe. Twoja baza jest teraz bardziej elastyczna, odporna na zmiany w logice biznesowej i często bardziej wydajna w operacjach złączeń. Zrozumiałeś różnicę między kluczem naturalnym a surogatowym i wiesz, kiedy stosować każde z tych rozwiązań.

Zadanie 13: Obsługa relacji wiele-do-wielu

Cel zadania

Zrozumienie, jak modelować i implementować relację wiele-do-wielu (N:M) za pomocą tabeli pośredniczącej (łączącej), co jest bardzo częstym przypadkiem w projektowaniu baz danych.

Scenariusz

Pojawia się nowe wymaganie od dziekanatu. Okazuje się, że jeden przedmiot może być prowadzony przez kilku wykładowców jednocześnie (np. wykład prowadzi profesor, a ćwiczenia doktor). Dotychczasowy model, w którym tabela Przedmioty miała jedno pole id_wykladowcy, zakładał relację jeden-do-wielu (jeden wykładowca mógł mieć wiele przedmiotów, ale przedmiot miał tylko jednego wykładowcę). Ta architektura jest już niewystarczająca. Twoim zadaniem jest przebudowanie schematu bazy danych, aby poprawnie obsłużyć nową relację: wiele-do-wielu. Musisz zrozumieć, że nie da się tego zrobić, po prostu dodając więcej kolumn w tabeli Przedmioty. Prawidłowym rozwiązaniem jest stworzenie nowej, trzeciej tabeli, zwanej tabelą asocjacyjną (łączącą), na przykład o nazwie Prowadzacy_Przedmioty. Tabela ta będzie zawierać tylko dwa klucze obce: jeden wskazujący na przedmiot (id_przedmiotu) i drugi na wykładowcę (id_wykladowcy). Razem będą one tworzyć złożony klucz główny. Musisz usunąć starą kolumnę id_wykladowcy z tabeli Przedmioty i zaimplementować nową strukturę, która pozwoli na przypisanie dowolnej liczby wykładowców do dowolnej liczby przedmiotów.

Wykonanie krok po kroku

  1. Przeanalizuj problem: jeden wykładowca może uczyć wielu przedmiotów, a jeden przedmiot może być uczony przez wielu wykładowców. To jest klasyczna relacja N:M.
  2. Zmodyfikuj tabelę Przedmioty, usuwając z niej bezpośrednie powiązanie z wykładowcą.
  3. -- W bazie uczelnia_3nf_final
    ALTER TABLE Przedmioty DROP FOREIGN KEY Przedmioty_ibfk_1;
    ALTER TABLE Przedmioty DROP COLUMN id_wykladowcy;
  4. Stwórz nową tabelę pośredniczącą Prowadzacy_Przedmioty.
  5. CREATE TABLE Prowadzacy_Przedmioty (
        id_przedmiotu INT,
        id_wykladowcy INT,
        PRIMARY KEY (id_przedmiotu, id_wykladowcy),
        FOREIGN KEY (id_przedmiotu) REFERENCES Przedmioty(id_przedmiotu),
        FOREIGN KEY (id_wykladowcy) REFERENCES Wykladowcy(id_wykladowcy)
    );
  6. Zasil nową tabelę przykładowymi danymi, aby pokazać, że jeden przedmiot może mieć wielu prowadzących.
  7. -- Zakładając, że mamy przedmioty i wykładowców z odpowiednimi ID
    INSERT INTO Prowadzacy_Przedmioty (id_przedmiotu, id_wykladowcy) VALUES (1, 1), (1, 2);
    -- Powyższy zapis oznacza, że przedmiot o ID=1 jest prowadzony przez wykładowców o ID=1 i ID=2
  8. Napisz zapytanie, które pokaże wszystkich wykładowców dla danego przedmiotu, używając nowej tabeli.
  9. SELECT p.nazwa_przedmiotu, w.imie_wykladowcy, w.nazwisko_wykladowcy
    FROM Przedmioty p
    JOIN Prowadzacy_Przedmioty pp ON p.id_przedmiotu = pp.id_przedmiotu
    JOIN Wykladowcy w ON pp.id_wykladowcy = w.id_wykladowcy
    WHERE p.kod_przedmiotu = 'CS101'; -- lub inny kod

Objaśnienia

Relacji wiele-do-wielu (N:M) nie da się zaimplementować bezpośrednio w modelu relacyjnym. Rozwiązuje się ją zawsze za pomocą dodatkowej tabeli, zwanej tabelą pośredniczącą, łączącą lub asocjacyjną. Taka tabela przechowuje pary kluczy obcych z dwóch tabel, które chcemy połączyć. Złożony klucz główny tej tabeli, składający się z obu kluczy obcych, zapewnia unikalność powiązań. Tabela pośrednicząca może również zawierać dodatkowe atrybuty opisujące samą relację (np. rolę wykładowcy na danym przedmiocie: 'wykładowca', 'prowadzący ćwiczenia').

Wnioski

Nauczyłeś się modelować i implementować najbardziej elastyczny typ relacji – wiele-do-wielu. Twój schemat bazy danych jest teraz w stanie obsłużyć bardziej złożone i realistyczne scenariusze biznesowe, co świadczy o jego dojrzałości i poprawności projektowej.

Zadanie 14: Podsumowanie procesu normalizacji i ocena finalnego schematu

Cel zadania

Dokonanie przeglądu całego procesu normalizacji, od postaci nienormalizowanej do zrefaktoryzowanej trzeciej postaci normalnej. Podsumowanie zalet finalnego schematu i zrozumienie kompromisów związanych z normalizacją.

Scenariusz

Twoja praca nad bazą danych dobiegła końca. Przeszedłeś długą drogę od jednego, chaotycznego arkusza kalkulacyjnego do eleganckiej, w pełni znormalizowanej i elastycznej struktury relacyjnej. Twoim ostatnim zadaniem jest przygotowanie prezentacji dla całego zespołu IT oraz pracowników dziekanatu, w której podsumujesz cały proces. Musisz przedstawić "przed" i "po" – pokazać schemat początkowy i wszystkie jego wady, a następnie zaprezentować finalny diagram bazy danych, omawiając każdą tabelę i jej przeznaczenie. Musisz jasno wyjaśnić, jakie korzyści przyniosła normalizacja: minimalizację redundancji, eliminację anomalii, integralność danych dzięki kluczom obcym, elastyczność na przyszłe zmiany (jak dodanie relacji N:M czy zmiana kodów przedmiotów). Musisz również wspomnieć o potencjalnych kompromisach. Czy jest coś, co stało się trudniejsze po normalizacji? Z pewnością zapytania stały się bardziej skomplikowane i wymagają wielu złączeń. Musisz jednak wykazać, że korzyści płynące z dobrze zorganizowanej struktury wielokrotnie przewyższają tę niedogodność, którą zresztą można zniwelować za pomocą widoków. Twoje podsumowanie ma być dowodem na to, że normalizacja nie jest celem samym w sobie, ale potężnym narzędziem prowadzącym do stworzenia solidnej, niezawodnej i łatwej w utrzymaniu bazy danych.

Wykonanie krok po kroku

  1. Narysuj lub opisz schemat początkowy (jedna tabela rejestr_ocen) i wypunktuj jego wady:
    • Ogromna redundancja danych.
    • Anomalie aktualizacji, wstawiania i usuwania.
    • Brak integralności danych.
    • Trudności w utrzymaniu i modyfikacji.
  2. Zaprezentuj finalny schemat bazy uczelnia_3nf_final, składający się z tabel: Wydzialy, Kierunki, Studenci, Wykladowcy, Przedmioty, Oceny, Prowadzacy_Przedmioty.
  3. Finalny schemat (3NF z kluczami surogatowymi i relacją N:M): - Wydzialy (id_wydzialu, nazwa, adres) - Kierunki (id_kierunku, nazwa, id_wydzialu) - Studenci (nr_albumu, imie, nazwisko, email, id_kierunku) - Wykladowcy (id_wykladowcy, imie, nazwisko, stopien) - Przedmioty (id_przedmiotu, kod, nazwa) - Prowadzacy_Przedmioty (id_przedmiotu, id_wykladowcy) - Oceny (id_oceny, nr_albumu, id_przedmiotu, ocena, data)
    Widok zależności kluczy w finalnym schemacie: +------------+ +-----------+ +----------+ | Wydzialy | | Kierunki | | Studenci | |------------| 1 * |-----------| 1 * |----------| | id_wydzialu|------|id_kierunku|------|nr_albumu | | ... | |id_wydzialu| |id_kierunku| +------------+ +-----------+ +----------+ | * | +-------+ | Oceny | |-------| |nr_albumu| |id_przedmiotu| +-------+ | * | +------------+ +-----------------------+ +------------+ | Wykladowcy | | Prowadzacy_Przedmioty | | Przedmioty | |------------| * 1 |-----------------------| 1 * |------------| |id_wykladowcy|-----|id_wykladowcy |------|id_przedmiotu| | ... | |id_przedmiotu | | ... | +------------+ +-----------------------+ +------------+ Legenda: `---|` oznacza "jeden" `---*` oznacza "wiele" Relacje: - Jeden Wydział ma wiele Kierunków. - Jeden Kierunek ma wielu Studentów. - Jeden Student ma wiele Ocen. - Jeden Przedmiot ma wiele Ocen. - Jeden Wykładowca może prowadzić wiele Przedmiotów (przez tabelę Prowadzący). - Jeden Przedmiot może być prowadzony przez wielu Wykładowców (przez tabelę Prowadzący).
  4. Wypunktuj zalety finalnego schematu:
    • Minimalna redundancja: Każda informacja jest przechowywana tylko w jednym miejscu.
    • Brak anomalii: Zmiana danych w jednym miejscu nie wpływa na spójność reszty bazy.
    • Integralność danych: Klucze obce i ograniczenia (constraints) zapewniają, że dane są spójne i poprawne.
    • Elastyczność: Łatwość rozbudowy o nowe byty i relacje.
    • Przejrzystość: Każda tabela odpowiada za jeden, logiczny koncept.
  5. Omów kompromis:
    • Złożoność zapytań: Pobieranie danych wymaga stosowania złączeń (JOIN).
    • Potencjalny spadek wydajności: W skrajnych przypadkach bardzo duża liczba złączeń może być wolniejsza niż zapytanie do denormalizowanej tabeli (co jest jednak rzadkością i tematem zaawansowanej optymalizacji).
  6. Wskaż, jak widoki (VIEW) pomagają zniwelować problem złożoności zapytań dla użytkowników końcowych.

Wnioski

Przeprowadziłeś kompleksowy proces normalizacji bazy danych, przechodząc przez wszystkie kluczowe etapy. Zrozumiałeś teoretyczne podstawy (zależności funkcyjne) i potrafisz zastosować je w praktyce do dekompozycji tabel. Ostateczny schemat jest zgodny z najlepszymi praktykami projektowania baz danych, co czyni go solidnym fundamentem dla każdej aplikacji.