Dataczwartek, 13 sierpnia 2026 Czas18:25:10
← Bazy danych i SQL

Lekcja 4. Relacje i łączenie tabel — JOIN

Średni

Po co się tego uczymy?

Dane rzadko siedzą w jednej tabeli. Klienci są w jednej tabeli, produkty w drugiej, a zamówienia w trzeciej — i żeby odpowiedzieć na pytanie "kto co kupił", musisz połączyć te trzy tabele naraz. Do tego służy JOIN.

Teoria

JOIN łączy wiersze z dwóch (albo więcej) tabel na podstawie wspólnej wartości — najczęściej klucza głównego jednej tabeli i klucza obcego drugiej.

Dwa najważniejsze rodzaje JOIN-a:
- INNER JOIN — zwraca tylko te wiersze, które mają dopasowanie w OBU tabelach. Jeśli klient nie złożył żadnego zamówienia, w wyniku INNER JOIN w ogóle się nie pojawi.
- LEFT JOIN — zwraca WSZYSTKIE wiersze z lewej (pierwszej) tabeli, nawet jeśli nie mają dopasowania w drugiej tabeli — wtedy brakujące dane są wypełniane wartością NULL.

Składnia: JOIN zawsze idzie w parze ze słowem kluczowym ON, które mówi, po jakich kolumnach łączymy tabele (Zamowienia.id_klienta = Klienci.id_klienta).

Schemat

INNER JOIN Klienci Zamówienia tylko wiersze pasujące w OBU tabelach LEFT JOIN Klienci Zamówienia WSZYSCY klienci, nawet bez zamówień

Przykład z życia

Wyobraź sobie sklep muzyczny z trzema "półkami": klienci, produkty i zamówienia. Żeby wygenerować fakturę albo raport "co kupił Jan Kowalski", musisz połączyć dane z tych trzech osobnych miejsc w jeden spójny wynik — dokładnie to robi JOIN.

Kod (SQL)

CREATE TABLE Klienci (
    id_klienta INT AUTO_INCREMENT PRIMARY KEY,
    imie VARCHAR(50) NOT NULL,
    nazwisko VARCHAR(50) NOT NULL
);

CREATE TABLE Produkty (
    id_produktu INT AUTO_INCREMENT PRIMARY KEY,
    nazwa VARCHAR(100) NOT NULL,
    cena DECIMAL(10,2) NOT NULL
);

CREATE TABLE Zamowienia (
    id_zamowienia INT AUTO_INCREMENT PRIMARY KEY,
    id_klienta INT NOT NULL,
    id_produktu INT NOT NULL,
    ilosc INT NOT NULL,
    FOREIGN KEY (id_klienta) REFERENCES Klienci(id_klienta),
    FOREIGN KEY (id_produktu) REFERENCES Produkty(id_produktu)
);

-- Kto co zamówił? Łączymy trzy tabele naraz

SELECT Klienci.imie, Klienci.nazwisko, Produkty.nazwa, Zamowienia.ilosc
FROM Zamowienia
INNER JOIN Klienci ON Zamowienia.id_klienta = Klienci.id_klienta
INNER JOIN Produkty ON Zamowienia.id_produktu = Produkty.id_produktu;

-- Wszyscy klienci, także ci, którzy jeszcze nic nie zamówili

SELECT Klienci.imie, Zamowienia.id_zamowienia
FROM Klienci
LEFT JOIN Zamowienia ON Klienci.id_klienta = Zamowienia.id_klienta;

Komentarz i wyjaśnienie kodu

Pierwsze zapytanie łączy trzy tabele: zaczyna od Zamowienia i INNER JOIN-uje kolejno Klienci oraz Produkty po odpowiednich kluczach — dzięki temu w jednym wyniku widzisz imię klienta, nazwę produktu i ilość, mimo że te dane fizycznie leżą w trzech różnych tabelach. Drugie zapytanie używa LEFT JOIN, więc pokaże też klientów, którzy nigdy nic nie zamówili — dla nich kolumna id_zamowienia będzie po prostu pusta (NULL). To bardzo ważna różnica: INNER JOIN "gubi" takich klientów, LEFT JOIN ich zachowuje.

Ćwiczenie samodzielne

Zmień pierwsze zapytanie tak, żeby pokazywało tylko zamówienia o ilości większej niż 1 sztuka (dodaj WHERE po wszystkich JOIN-ach). Potem zamień jeden z INNER JOIN na LEFT JOIN i sprawdź, jak zmienia się liczba wierszy w wyniku.

Zadania do pracy własnej

  1. Zadanie 1. JOIN w sklepie muzycznym

    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.
  2. Zadanie 2. JOIN w aptece

    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ł.
  3. Zadanie 3. JOIN w siłowni

    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: Siłownia FitZone (.sql.gz). Zaimportuj spakowany plik SQL w XAMPP/phpMyAdmin, a następnie wykonaj zapytania.

    1. Wyświetl zajęcia wraz z imieniem i nazwiskiem trenera.
    2. Wyświetl klientów z karnetem Premium.
    3. Policz liczbę zajęć prowadzonych przez każdego trenera.
    4. Policz zapisy na każde zajęcia.
    5. Wyświetl klientów zapisanych na Trening siłowy.
    6. Pokaż zajęcia rozpoczynające się po godzinie 17:00.
    7. Pokaż klientów, którzy zapisali się na więcej niż jedne zajęcia.
    8. Wyświetl raport: klient, typ karnetu, zajęcia, trener, data zapisu.
    9. Policz zapisy według dnia.
    10. Pokaż trenerów, którzy prowadzą zajęcia z co najmniej dwoma zapisami.

Typowe błędy

Najgroźniejszy błąd to zapomnienie warunku ON — bez niego SQL zwróci iloczyn kartezjański, czyli każdy wiersz z pierwszej tabeli połączony z każdym wierszem z drugiej (przy dużych tabelach to może być milion niepotrzebnych wierszy). Drugi błąd to użycie INNER JOIN tam, gdzie potrzebny jest LEFT JOIN, przez co "znikają" rekordy bez dopasowania (np. klienci bez zamówień w raporcie sprzedaży). Trzeci: mylenie kolejności tabel w LEFT JOIN — LEFT JOIN zachowuje wszystkie wiersze z tabeli PIERWSZEJ (lewej), nie drugiej.

Nawiązanie do egzaminu zawodowego

Łączenie tabel to jeden z filarów efektu "stosuje strukturalny język zapytań SQL" w INF.03.4 — na egzaminie praktycznym niemal zawsze trzeba wyciągnąć dane rozproszone po kilku tabelach (np. cennik, miejscowość i rodzaj w przykładowym zadaniu z informatora CKE), co bez JOIN-a jest niemożliwe.