Dataczwartek, 13 sierpnia 2026 Czas18:37:23
← Bazy danych i SQL

Lekcja 9. Więzy integralności w SQL

Średni

Po co się tego uczymy?

Bez żadnych zasad baza danych pozwoliłaby wpisać cokolwiek — ujemną cenę, zamówienie bez klienta, dwóch użytkowników z tym samym adresem e-mail. Więzy integralności to strażnik, który tego pilnuje na poziomie samej bazy, niezależnie od tego, czy aplikacja przypadkiem ma błąd.

Teoria

Więzy integralności (ang. constraints) to zasady, które pilnują, żeby dane w bazie miały sens i nie przeczyły sobie nawzajem. Bez nich baza pozwoliłaby np. dodać zamówienie klienta, który nie istnieje, albo produkt z ceną -50 zł.

Najważniejsze rodzaje więzów:
PRIMARY KEY — unikalny identyfikator rekordu (nie może się powtórzyć, nie może być pusty).
FOREIGN KEY — powiązanie z rekordem w innej tabeli (nie pozwala wpisać np. zamówienia z nieistniejącym id_klienta).
UNIQUE — wartość w kolumnie nie może się powtórzyć (np. adres e-mail).
NOT NULL — kolumna zawsze musi mieć wartość.
CHECK — sprawdza dowolny warunek logiczny (np. cena musi być większa od zera).
DEFAULT — ustawia wartość domyślną, jeśli nie podano innej.

Przykład tabeli z kompletem więzów integralności:

CREATE TABLE Produkty (
    id_produktu INT AUTO_INCREMENT PRIMARY KEY,
    nazwa VARCHAR(100) NOT NULL,
    cena DECIMAL(10,2) NOT NULL CHECK (cena > 0),
    kod_produktu VARCHAR(20) UNIQUE,
    ilosc_na_stanie INT DEFAULT 0
);

Przykład z życia

Formularz rejestracji w serwisie internetowym — gdy próbujesz założyć konto na już zajęty adres e-mail, dostajesz błąd. To w praktyce więzu UNIQUE na kolumnie e-mail w bazie danych, nawet jeśli sama aplikacja też to sprawdza.

Kod (SQL)

CREATE TABLE Klienci (
    id_klienta INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(100) NOT NULL UNIQUE
);

CREATE TABLE Zamowienia (
    id_zamowienia INT AUTO_INCREMENT PRIMARY KEY,
    id_klienta INT NOT NULL,
    kwota DECIMAL(10,2) NOT NULL CHECK (kwota > ),
    status VARCHAR(20) DEFAULT 'nowe',
    FOREIGN KEY (id_klienta) REFERENCES Klienci(id_klienta)
);

-- to zadziała:

INSERT INTO Klienci (email) VALUES ('jan@przyklad.pl');
INSERT INTO Zamowienia (id_klienta, kwota) VALUES (1, 150.00);

-- to zgłosi błąd — narusza FOREIGN KEY (nie ma klienta o id 999):

-- INSERT INTO Zamowienia (id_klienta, kwota) VALUES (999, 50.00);


-- to zgłosi błąd — narusza UNIQUE (e-mail już istnieje):

-- INSERT INTO Klienci (email) VALUES ('jan@przyklad.pl');

Komentarz i wyjaśnienie kodu

Tabela Zamowienia ma aż trzy różne więzy naraz: FOREIGN KEY pilnuje, że id_klienta wskazuje na istniejącego klienta; CHECK pilnuje, że kwota jest dodatnia; DEFAULT ustawia status na 'nowe', jeśli nic innego nie podamy. Dwa zakomentowane polecenia na końcu pokazują, co konkretnie by się nie udało i dlaczego — spróbuj je odkomentować i uruchomić, żeby zobaczyć rzeczywisty komunikat błędu.

Ćwiczenie samodzielne

Dodaj do tabeli Produkty (z wcześniejszych lekcji) więz CHECK pilnujący, że cena zawsze jest większa od zera, oraz więz UNIQUE na kolumnie nazwa.

Zadania do pracy własnej

  1. Zadanie 1. Test kluczy obcych w szkole

    Uwaga przed importem: plik z bazą jest spakowany jako .gz. phpMyAdmin w XAMPP przyjmuje takie pliki bez rozpakowywania. Jeżeli po pobraniu nazwa wygląda np. sklep_muzyczny.sql_.gz i import nie przejdzie, zmień nazwę pliku na sklep_muzyczny.sql.gz, a potem wybierz go w zakładce Importuj.

    Baza do pracy: Szkoła relacje (.sql.gz). Zaimportuj spakowany plik SQL w XAMPP/phpMyAdmin, a następnie wykonaj zapytania.

    1. Wyświetl uczniów wraz z nazwą klasy.
    2. Wyświetl uczniów wraz z numerem legitymacji.
    3. Wyświetl uczniów i przedmioty, na które uczęszczają.
    4. Policz uczniów w każdej klasie.
    5. Policz ilu uczniów ma każdy przedmiot.
    6. Wyświetl uczniów z klasy 1P i ich przedmioty.
    7. Wyświetl klasy wraz z wychowawcą i liczbą uczniów.
    8. Wyświetl uczniów, którzy mają więcej niż jeden przedmiot.
    9. Wyświetl przedmioty, na które nie zapisano żadnego ucznia.
    10. Wyświetl pełny raport: klasa, uczeń, legitymacja, przedmiot.
  2. Zadanie 2. Integralność zamówień

    Uwaga przed importem: plik z bazą jest spakowany jako .gz. phpMyAdmin w XAMPP przyjmuje takie pliki bez rozpakowywania. Jeżeli po pobraniu nazwa wygląda np. sklep_muzyczny.sql_.gz i import nie przejdzie, zmień nazwę pliku na sklep_muzyczny.sql.gz, a potem wybierz go w zakładce Importuj.

    Baza do pracy: Sklep muzyczny (.sql.gz). Zaimportuj spakowany plik SQL w XAMPP/phpMyAdmin, a następnie wykonaj zapytania.

    1. Wyświetl zamówienia: imię, nazwisko, produkt, ilość, data.
    2. Wyświetl zamówienia wraz z kategorią produktu.
    3. Wyświetl klientów i produkty kupione po 1 października 2025.
    4. Wyświetl produkty, które zostały zamówione przez klientów z Gdańska.
    5. Wyświetl klienta, produkt i wartość pozycji zamówienia: ilość * cena.
    6. Wyświetl wszystkie produkty wraz z nazwą kategorii.
    7. Wyświetl klientów, którzy kupili instrumenty.
    8. Wyświetl zamówienia posortowane według nazwiska klienta i daty.
    9. Wyświetl klienta, miasto, produkt i kategorię dla każdego zamówienia.
    10. Wyświetl produkty zamówione w liczbie większej niż 2 sztuki.
  3. Zadanie 3. Integralność sprzedaży leków

    Uwaga przed importem: plik z bazą jest spakowany jako .gz. phpMyAdmin w XAMPP przyjmuje takie pliki bez rozpakowywania. Jeżeli po pobraniu nazwa wygląda np. sklep_muzyczny.sql_.gz i import nie przejdzie, zmień nazwę pliku na sklep_muzyczny.sql.gz, a potem wybierz go w zakładce Importuj.

    Baza do pracy: Apteka Zdrowie (.sql.gz). Zaimportuj spakowany plik SQL w XAMPP/phpMyAdmin, a następnie wykonaj zapytania.

    1. Wyświetl wszystkie leki wraz z kategorią i producentem.
    2. Wyświetl leki, których stan magazynowy jest mniejszy niż 50.
    3. Policz liczbę leków w każdej kategorii.
    4. Oblicz średnią cenę leków według kategorii.
    5. Oblicz wartość magazynu każdego leku: cena * ilość_magazyn.
    6. Pokaż trzy najdroższe leki.
    7. Wyświetl sprzedaż: nazwa leku, ilość, data, wartość sprzedaży.
    8. Oblicz sumę sprzedanych sztuk dla każdego leku.
    9. Pokaż producentów, których leki były sprzedawane.
    10. Pokaż kategorie, w których średnia cena przekracza 20 zł.

Typowe błędy

Częsty błąd to całkowite pominięcie więzów integralności "na razie, dodam je później" — w praktyce nikt ich potem nie dodaje, a błędne dane już siedzą w bazie. Drugi błąd to zbyt restrykcyjny NOT NULL na kolumnie, która czasem faktycznie powinna być pusta (np. data zakończenia projektu, który jeszcze trwa). Trzeci: zapominanie, że FOREIGN KEY wymaga, żeby tabela nadrzędna (ta, na którą wskazujemy) istniała PRZED utworzeniem tabeli z kluczem obcym.

Nawiązanie do egzaminu zawodowego

Więzy integralności są wprost wymienione w efekcie INF.03.4.1 ("posługuje się pojęciami dotyczącymi baz danych") i w praktycznym efekcie "tworzy relacyjne bazy danych zgodnie z projektem" — dobrze zaprojektowana baza na egzaminie powinna mieć kompletne klucze główne, obce i podstawowe ograniczenia.