Łączenie tabel - INNER JOIN - LEFT JOIN

INF.03 · Bazy danych · SQL

Łączenie tabel: JOIN

Dane w bazie są rozdzielone na kilka tabel: osobno uczniowie, osobno oceny, osobno nauczyciele. JOIN skleja je z powrotem w jedną tabelę wynikową. Na tej stronie działa symulator MySQL z gotową bazą szkola. Wpisuj zapytania, klikaj Wykonaj (albo Ctrl+Enter) i porównuj wyniki. Kliknięcie nazwy tabeli w drzewku po lewej pokazuje jej zawartość.

1

Po co łączyć tabele?

W tabeli oceny nie zapisujemy imienia i nazwiska ucznia przy każdej ocenie, tylko jego numer uczen_id. Dzięki temu dane się nie powtarzają, a zmiana nazwiska wymaga poprawki w jednym miejscu. Ceną jest to, że żeby zobaczyć „Jan Kowalski – Matematyka – 5”, trzeba połączyć tabele po wspólnym polu. Do tego służy JOIN.

uczniowie
uczen_idimienazwiskoklasa_id
1JanKowalski1
2AnnaNowak1
3PiotrWiśniewski2
4OlaZielińska2
5KamilLewandowski3
oceny
ocena_iduczen_idnauczyciel_idprzedmiotocena
111Matematyka5
212Polski4
323Angielski5
421Matematyka3
542Polski6
641Matematyka2
713Angielski4

W bazie są jeszcze tabele nauczyciele (4 osoby, w tym Marek Kamiński, który nie wystawił żadnej oceny) oraz klasy (4A, 4B, 4C). Piotr i Kamil nie mają jeszcze ocen. Te braki przydadzą się przy LEFT i RIGHT JOIN.

Schemat do zapamiętania

Klucz główny w jednej tabeli (uczniowie.uczen_id) i klucz obcy w drugiej (oceny.uczen_id) mają te same wartości. Po nich łączymy tabele: wiersz oceny z uczen_id = 1 należy do ucznia nr 1.

2

Szybkie przypomnienie: SELECT na jednej tabeli

JOIN to rozszerzenie zwykłego SELECT, więc najpierw przypomnij sobie jego budowę:

SELECT kolumny        -- co pokazać (* = wszystko)
FROM tabela           -- skąd
WHERE warunek         -- które wiersze (opcjonalnie)
ORDER BY kolumna;     -- jak posortować (ASC rosnąco, DESC malejąco)
3

INNER JOIN: tylko pasujące wiersze

INNER JOIN dołącza drugą tabelę i paruje wiersze, dla których warunek ON jest spełniony. Wiersze bez pary nie pojawiają się w wyniku.

SELECT uczniowie.imie, uczniowie.nazwisko, oceny.przedmiot, oceny.ocena
FROM uczniowie
INNER JOIN oceny
ON uczniowie.uczen_id = oceny.uczen_id;
1 · SELECTkolumny z obu tabel, najlepiej w postaci tabela.kolumna
2 · FROMpierwsza tabela, czyli „lewa”
3 · JOINdruga tabela, czyli „prawa”
4 · ONwarunek łączenia: klucz główny = klucz obcy
Schemat do zapamiętania
SELECT …
FROM tabela1
JOIN tabela2 ON tabela1.klucz = tabela2.klucz;

FROM – JOIN – ON. W ON zawsze stoi para: klucz główny = klucz obcy. Samo JOIN oznacza to samo co INNER JOIN.

Zobacz, jak JOIN dobiera pary

Przykład pomocniczy: szafki szkolne. Niektóre szafki są wolne (uczen_id = NULL), a Anna nie ma szafki. Wybierz rodzaj JOIN i przechodź krok po kroku.

LP

    
uczniowie (lewa)
szafki (prawa)
wynik

Teraz prawdziwa baza. Zwróć uwagę, że w wyniku nie ma Piotra ani Kamila, bo nie mają ocen:

Ile wierszy zwróci powyższy INNER JOIN?

4

Nazwy kolumn i aliasy

Kolumna uczen_id jest w obu tabelach. Gdy napiszesz ją bez nazwy tabeli, MySQL nie wie, o którą chodzi, i zgłasza błąd #1052 ambiguous (niejednoznaczna). Uruchom:

Żeby nie pisać za każdym razem długich nazw tabel, nadajemy im aliasy, czyli krótkie przezwiska, np. u i o. Kolumnom w wyniku też możesz nadać czytelne nazwy przez AS.

Schemat do zapamiętania
SELECT u.imie, o.ocena AS "Ocena"
FROM uczniowie u
JOIN oceny o ON u.uczen_id = o.uczen_id;

Alias tabeli nadajesz w FROM/JOIN, a używasz go wszędzie, także w SELECT, który stoi wyżej. Po nadaniu aliasu pełna nazwa tabeli przestaje działać.

5

JOIN razem z WHERE i ORDER BY

Po połączeniu tabel możesz filtrować i sortować wynik tak samo jak zwykle. Ważna jest tylko kolejność części zapytania:

Schemat do zapamiętania
SELECT … FROM … JOIN … ON … WHERE … GROUP BY … ORDER BY … LIMIT …

JOIN zawsze zaraz po FROM, przed WHERE. Najpierw sklejasz tabele, potem wybierasz wiersze, na końcu sortujesz.

Źle: WHERE przed JOINSELECT … FROM uczniowie u WHERE u.imie = 'Jan' JOIN oceny o ON …
DobrzeSELECT … FROM uczniowie u JOIN oceny o ON … WHERE u.imie = 'Jan'
6

LEFT JOIN: wszystko z lewej tabeli

LEFT JOIN zwraca wszystkie wiersze z lewej tabeli (tej z FROM), nawet jeśli nie mają pary. Brakujące dane z prawej tabeli zostają wypełnione wartością NULL.

Klasyczne zastosowanie, które często pojawia się w arkuszach: znajdź wiersze bez pary. Po LEFT JOIN bierzesz tylko te wiersze, w których kolumna z prawej tabeli jest NULL:

Schemat do zapamiętania

INNER = tylko pary. LEFT = cała lewa tabela, a puste miejsca to NULL. „Kto nie ma…?” to prawie zawsze LEFT JOIN + WHERE prawa.klucz IS NULL.

Źle: = NULL nigdy nie jest prawdąWHERE o.ocena_id = NULL
DobrzeWHERE o.ocena_id IS NULL

Ile wierszy zwróci uczniowie LEFT JOIN oceny?

7

RIGHT JOIN i FULL JOIN

RIGHT JOIN działa odwrotnie niż LEFT: zachowuje wszystkie wiersze z prawej tabeli (tej z JOIN). Każdy RIGHT JOIN można zapisać jako LEFT JOIN, zamieniając tabele miejscami. W praktyce i w odpowiedziach do arkuszy częściej spotkasz LEFT.

FULL JOIN (wszystko z obu stron) istnieje w standardzie SQL, ale MySQL i MariaDB go nie obsługują, więc w phpMyAdmin z XAMPP dostaniesz błąd. Ten sam wynik uzyskasz, sklejając LEFT JOIN i RIGHT JOIN słowem UNION:

RodzajCo zwracaBrakujące dane
INNER JOINtylko pary pasujące w obu tabelach–
LEFT JOINwszystko z lewej (FROM) + pasujące z prawejNULL po prawej
RIGHT JOINwszystko z prawej (JOIN) + pasujące z lewejNULL po lewej
FULL JOINwszystko z obu stron; w MySQL przez LEFT … UNION … RIGHTNULL po obu stronach
CROSS JOINkażdy wiersz z każdym (iloczyn kartezjański)–
8

Łączenie trzech (i więcej) tabel

Każdą kolejną tabelę dołączasz kolejnym JOIN … ON. Tabela oceny jest tu „łącznikiem”, bo ma klucze obce do obu pozostałych.

Schemat do zapamiętania
FROM uczniowie u
JOIN oceny o       ON u.uczen_id = o.uczen_id
JOIN nauczyciele n ON o.nauczyciel_id = n.nauczyciel_id

Ile tabel, tyle minus jeden warunków ON. 3 tabele to 2 JOIN-y.

Starszy zapis: przecinek i WHERE

W starszych materiałach i w wielu odpowiedziach do arkuszy egzaminacyjnych łączenie wygląda tak: tabele wypisane po przecinku, a warunek łączenia w WHERE. Wynik jest taki sam jak przy INNER JOIN.

9

JOIN z funkcjami: COUNT, AVG i GROUP BY

Na egzaminie często trzeba coś policzyć dla każdej osoby albo grupy, np. liczbę ocen każdego ucznia czy średnią w każdej klasie. Łączysz tabele, a potem grupujesz przez GROUP BY:

Schemat do zapamiętania

COUNT(kolumna) pomija NULL, a COUNT(*) liczy wiersze. Przy LEFT JOIN licz kolumnę z prawej tabeli, wtedy osoby bez danych dostaną 0, a nie 1.

Warunek na wynik funkcji, np. „średnia powyżej 4”, piszesz w HAVING, a nie w WHERE.

10

Najczęstsze błędy przy JOIN

KodCo zobaczyszPrzyczyna i poprawka
#1052Column '…' in field list is ambiguousKolumna jest w dwóch tabelach. Dopisz tabelę lub alias: u.uczen_id.
#1054Unknown column 'uczniowie.imie'Tabela ma alias, więc trzeba pisać u.imie. Inna możliwość: literówka albo tekst bez apostrofów.
#1066Not unique table/aliasDwa razy ten sam alias albo ta sama tabela bez aliasów.
#1064… near 'JOIN …'JOIN po WHERE albo FULL JOIN, którego MySQL nie ma.
#1111Invalid use of group functionCOUNT/AVG w WHERE. Przenieś warunek do HAVING.
brak ONdziwnie dużo wierszyIloczyn kartezjański: każdy z każdym. Dopisz ON a.klucz = b.klucz.
= NULLpusty wynikDo NULL porównujemy przez IS NULL / IS NOT NULL.
✎

Zadania

Napisz zapytanie i kliknij Sprawdź. Sprawdzarka porówna Twój wynik z wynikiem wzorcowego zapytania: liczbę kolumn, wszystkie wiersze i tam, gdzie to wymagane, kolejność. Nazwy kolumn w nagłówku nie mają znaczenia, ale kolejność kolumn musi być taka jak w poleceniu.

Z1. Oceny z nazwiskamiłatwe

Wyświetl imię i nazwisko ucznia oraz przedmiot i ocenę dla wszystkich wystawionych ocen.

Pokaż rozwiązanie
SELECT u.imie, u.nazwisko, o.przedmiot, o.ocena
FROM uczniowie u
JOIN oceny o ON u.uczen_id = o.uczen_id;
Z2. Wyniki z matematykiłatwe

Wyświetl imię, nazwisko i ocenę uczniów, którzy mają ocenę z przedmiotu Matematyka. Posortuj od najwyższej oceny.

Pokaż rozwiązanie
SELECT u.imie, u.nazwisko, o.ocena
FROM uczniowie u
JOIN oceny o ON u.uczen_id = o.uczen_id
WHERE o.przedmiot = 'Matematyka'
ORDER BY o.ocena DESC;
Z3. Wszyscy uczniowie i ich ocenyłatwe

Wyświetl imię i nazwisko każdego ucznia oraz jego oceny (przedmiot, ocena). Uczniowie bez ocen też mają się pojawić.

Pokaż rozwiązanie
SELECT u.imie, u.nazwisko, o.przedmiot, o.ocena
FROM uczniowie u
LEFT JOIN oceny o ON u.uczen_id = o.uczen_id;
Z4. Uczniowie bez ocenśrednie

Wyświetl imię i nazwisko uczniów, którzy nie mają żadnej oceny.

Pokaż rozwiązanie
SELECT u.imie, u.nazwisko
FROM uczniowie u
LEFT JOIN oceny o ON u.uczen_id = o.uczen_id
WHERE o.ocena_id IS NULL;
Z5. Kto wystawił ocenę?średnie

Wyświetl: imię i nazwisko ucznia, przedmiot, ocenę oraz nazwisko nauczyciela, który ją wystawił.

Pokaż rozwiązanie
SELECT u.imie, u.nazwisko, o.przedmiot, o.ocena, n.nazwisko
FROM uczniowie u
JOIN oceny o ON u.uczen_id = o.uczen_id
JOIN nauczyciele n ON o.nauczyciel_id = n.nauczyciel_id;
Z6. Nauczyciel bez ocenśrednie

Wyświetl imię i nazwisko nauczycieli, którzy nie wystawili jeszcze żadnej oceny.

Pokaż rozwiązanie
SELECT n.imie, n.nazwisko
FROM nauczyciele n
LEFT JOIN oceny o ON n.nauczyciel_id = o.nauczyciel_id
WHERE o.ocena_id IS NULL;
Z7. Ile ocen ma każdy uczeń?egzaminacyjne

Wyświetl imię, nazwisko i liczbę ocen każdego ucznia (uczniowie bez ocen mają mieć 0). Posortuj od największej liczby ocen.

Pokaż rozwiązanie
SELECT u.imie, u.nazwisko, COUNT(o.ocena_id) AS liczba
FROM uczniowie u
LEFT JOIN oceny o ON u.uczen_id = o.uczen_id
GROUP BY u.uczen_id, u.imie, u.nazwisko
ORDER BY liczba DESC;
Z8. Średnia klasyegzaminacyjne

Wyświetl nazwę klasy i średnią ocen jej uczniów, tylko dla klas, w których są jakieś oceny. Posortuj alfabetycznie po nazwie klasy. Potrzebne będą trzy tabele: klasy, uczniowie, oceny.

Pokaż rozwiązanie
SELECT k.nazwa, AVG(o.ocena) AS srednia
FROM klasy k
JOIN uczniowie u ON k.klasa_id = u.klasa_id
JOIN oceny o ON u.uczen_id = o.uczen_id
GROUP BY k.klasa_id, k.nazwa
ORDER BY k.nazwa;
★

Ściąga: JOIN

INNER JOIN

SELECT u.imie, o.ocena
FROM uczniowie u
JOIN oceny o ON u.uczen_id = o.uczen_id;

Tylko pary. ON: klucz główny = klucz obcy.

LEFT JOIN

FROM uczniowie u
LEFT JOIN oceny o ON u.uczen_id = o.uczen_id

Cała lewa tabela, brakujące dane to NULL.

Szukanie braków

LEFT JOIN oceny o ON …
WHERE o.ocena_id IS NULL

„Kto nie ma…?” → LEFT + IS NULL.

Trzy tabele

FROM a
JOIN b ON a.id = b.a_id
JOIN c ON b.c_id = c.id

Liczba tabel − 1 = liczba warunków ON.

Kolejność

SELECT … FROM … JOIN … ON …
WHERE … GROUP BY … HAVING …
ORDER BY … LIMIT …

JOIN zaraz po FROM, przed WHERE.

Liczenie

SELECT u.imie, COUNT(o.ocena_id)
FROM uczniowie u
LEFT JOIN oceny o ON …
GROUP BY u.uczen_id, u.imie

COUNT(kolumna) pomija NULL. Warunek na wynik funkcji → HAVING.

Na następnej lekcji: podzapytania i modyfikacja danych (UPDATE, DELETE z warunkiem).

Kontakt: mgzsp22@gmail.com

© 2025. Wszystkie prawa zastrzeżone.

error: Content is protected !!