INNER JOIN: łączenie danych z tabel
Połącz zamówienie z klientem i pozycję z produktem. Naucz się dobierać klucze, aliasy i liczyć wartości bez przypadkowego powielania.
Część bazodanowa INF.03Połącz dane, które rozdzieliłeś podczas projektowania
Zamówienie przechowuje klient_id, a tabela klienci zawiera imię. INNER JOIN łączy pasujące wiersze według warunku ON. Nie kopiuje trwale danych i nie tworzy nowej tabeli. Wynik SELECT może zawierać kolumny z obu źródeł.
SELECT z.id AS zamowienie, k.imie, z.data, z.status
FROM zamowienia z
INNER JOIN klienci k ON k.id = z.klient_id
ORDER BY z.id;Otrzymasz: zamówienie 1 — Ala, 2 — Jan, 3 — Ala, 4 — O’Neil. Ewa i Adam nie pojawiają się, ponieważ nie mają pasującego zamówienia. Dwa wystąpienia Ali są poprawne: klientka ma dwa zamówienia. Relacja 1:N może więc zwiększać liczbę wystąpień danych strony „1” w wyniku.
Alias tabeli i właściwy klucz
Litery z i k są aliasami tabel. Zapis z.id rozróżnia identyfikator zamówienia od k.id klienta. Użycie samego id przy dwóch tabelach z taką kolumną może dać błąd niejednoznacznej nazwy. Nie łącz po imieniu: dwie osoby mogą mieć to samo imię. Nie łącz też k.id = z.id tylko dlatego, że obie kolumny nazywają się id — oznaczają różne encje.
Klucz obcy pomaga utrzymać spójność, ale samo JOIN nie wymaga zadeklarowanego FK. Jest operacją na danych; zadziała także między innymi zgodnymi kolumnami. Obecność relacji w diagramie nie zwalnia z zapisania poprawnego ON w zapytaniu.
Wypróbuj zapytanie
SQLite — rzeczywisty silnik przeglądarki. MySQL / SQL Server — ograniczona emulacja składni. Wybierz tryb SQLite do natywnego LIKE. Pozostałe tryby nie są rzeczywistymi serwerami. Ścisłe typy, auto-ID i administrację ćwicz w prawdziwym SZBD.
ON opisuje dopasowanie, WHERE wybiera wynik
SELECT z.id, k.imie, k.miasto
FROM zamowienia z
INNER JOIN klienci k ON z.klient_id = k.id
WHERE k.miasto = 'Gdansk'
ORDER BY z.id;Wynik ma zamówienia 1, 3 i 4. ON wiąże zamówienie z właścicielem, a WHERE wybiera klientów z Gdanska. Przy INNER JOIN wiele warunków można logicznie przenosić między ON i WHERE, lecz ich wyraźny podział ułatwia czytanie. Przy złączeniach zewnętrznych taka zamiana może zmienić wynik — omówimy to w następnej części.
Wartość pozycji: ilość razy cena
SELECT p.zamowienie_id, pr.nazwa, p.ilosc, pr.cena,
p.ilosc * pr.cena AS wartosc
FROM pozycje p
INNER JOIN produkty pr ON pr.id = p.produkt_id
ORDER BY p.zamowienie_id, p.produkt_id;To sześć pozycji. Zamówienie 1 ma Klawiaturę 1 × 120 = 120 i Mysz 2 × 60 = 120; jego suma wynosi 240. SUM(cena) dałoby 180, więc pominęłoby ilość. Połączmy JOIN i GROUP BY:
SELECT p.zamowienie_id, SUM(p.ilosc * pr.cena) AS wartosc
FROM pozycje p
INNER JOIN produkty pr ON pr.id = p.produkt_id
GROUP BY p.zamowienie_id
ORDER BY p.zamowienie_id;Wynik: 1 → 240, 2 → 800, 3 → 75, 4 → 110. Nasz prosty model używa aktualnej ceny produktu. Prawdziwy sklep powinien zachować cenę zakupu na pozycji zamówienia, aby późniejsza zmiana cennika nie zmieniła historycznego rachunku.
Ten sam JOIN w innych środowiskach
Podstawowy zapis INNER JOIN … ON z pierwszego przykładu jest wspólny dla MySQL/MariaDB, SQL Server, Oracle 19c, Access oraz SQLite. Alias tabeli zapisaliśmy bez AS, co pasuje również do Oracle 19c. MySQL, SQL Server i Access dopuszczają AS dla aliasu tabeli. Nie myl tego z AS przy aliasie kolumny.
-- MySQL / SQL Server / Oracle / SQLite: trzy tabele
SELECT z.id, pr.nazwa, p.ilosc
FROM zamowienia z
INNER JOIN pozycje p ON p.zamowienie_id = z.id
INNER JOIN produkty pr ON pr.id = p.produkt_id
ORDER BY z.id, pr.id;
-- Access: jawne nawiasy zagnieżdżenia
SELECT z.id, pr.nazwa, p.ilosc
FROM (zamowienia AS z
INNER JOIN pozycje AS p ON p.zamowienie_id = z.id)
INNER JOIN produkty AS pr ON pr.id = p.produkt_id
ORDER BY z.id, pr.id;Access jest bardziej wymagający co do nawiasów w złożonych złączeniach. Edytor wykonuje SQLite i podstawowe JOIN w trybach porównawczych; nie stanowi testu parsera Access ani uprawnień serwera.
Sprawdź poziom szczegółowości
Po dołączeniu pozycji jedno zamówienie występuje tyle razy, ile ma pozycji. COUNT(*) liczy wtedy wiersze wyniku połączenia, a nie automatycznie liczbę zamówień. COUNT(DISTINCT z.id) może policzyć różne zamówienia w obsługujących go bazach; w Access użyj zapisanej kwerendy DISTINCT i policz jej wynik. Nie naprawiaj niepoprawnego ON przez dodanie DISTINCT — ukryłoby to objaw, a nie błąd.
Ćwiczenia
- Pokaż id i imiona klientów dla zamówień o statusie nowe.
- Pokaż nazwy oraz wartości pozycji zamówienia 4.
- Policz łączną wartość wszystkich pozycji w modelu ćwiczeniowym.
Rozwiązania
SELECT z.id, k.imie FROM zamowienia z
INNER JOIN klienci k ON k.id = z.klient_id
WHERE z.status = 'nowe' ORDER BY z.id;
SELECT pr.nazwa, p.ilosc * pr.cena AS wartosc
FROM pozycje p INNER JOIN produkty pr ON pr.id = p.produkt_id
WHERE p.zamowienie_id = 4 ORDER BY pr.id;
SELECT SUM(p.ilosc * pr.cena) AS lacznie
FROM pozycje p INNER JOIN produkty pr ON pr.id = p.produkt_id;1. 2 — Jan, 4 — O’Neil. 2. Mysz 60, Kabel 50. 3. 1225. Zwróć uwagę, że wyniki zostały wyliczone z cen i ilości, nie z liczby wierszy.
Źródła: MySQL JOIN, Oracle — złączenia, Access INNER JOIN. INF.03.4: zapytania do wielu tabel. Dalej: LEFT JOIN, inne złączenia i relacja N:M.

