JOIN SQL – INNER, LEFT, RIGHT i FULL JOIN w SQL Server na przykładach

join sql inner left right full

JOIN SQL – INNER, LEFT, RIGHT i FULL JOIN w SQL Server na przykładach

Dane w bazie rzadko leżą w jednej tabeli. Pracownicy są w jednej, działy w drugiej, zamówienia w trzeciej. Żeby zobaczyć zestawienie „Anna – Sprzedaż”, trzeba te tabele połączyć, a do tego służy klauzula JOIN.

W tym wpisie pokażemy, jak działa JOIN SQL w praktyce: cztery podstawowe rodzaje na jednej małej bazie, którą możesz sam utworzyć, oraz błędy, które najczęściej psują wyniki zapytań.

Do czego służy JOIN?

JOIN łączy wiersze z dwóch tabel na podstawie powiązanej kolumny. Zwykle jest to klucz obcy, który wskazuje na klucz główny drugiej tabeli. W naszym przykładzie kolumna IdDzialu w tabeli Pracownicy wskazuje na kolumnę IdDzialu w tabeli Dzialy.

Rodzaj JOIN decyduje o tym, co się stanie z wierszami, które nie mają pary w drugiej tabeli: zostaną pominięte czy pokazane z wartością NULL.

Dane do przykładów

Skopiuj skrypt do SQL Server Management Studio i uruchom go. Utworzy dwie małe tabele:

CREATE TABLE Dzialy (
    IdDzialu    INT PRIMARY KEY,
    NazwaDzialu NVARCHAR(50) NOT NULL
);

CREATE TABLE Pracownicy (
    IdPracownika INT PRIMARY KEY,
    Imie         NVARCHAR(50) NOT NULL,
    IdDzialu     INT NULL REFERENCES Dzialy(IdDzialu),
    Pensja       DECIMAL(10,2) NOT NULL
);

INSERT INTO Dzialy VALUES (1, N'Sprzedaż'), (2, N'IT'), (3, N'HR');

INSERT INTO Pracownicy VALUES
    (1, N'Anna',     1,    6500),
    (2, N'Marek',    2,    9200),
    (3, N'Ewa',      2,    8700),
    (4, N'Tomasz',   NULL, 5400),
    (5, N'Karolina', 1,    7100);

Dwie rzeczy są w tych danych celowe: Tomasz nie ma przypisanego działu (NULL), a dział HR nie ma żadnego pracownika. Dzięki temu zobaczysz, czym różnią się poszczególne rodzaje JOIN.

INNER JOIN – tylko wiersze, które pasują

INNER JOIN zwraca wyłącznie te wiersze, dla których znaleziono parę w obu tabelach. Słowo INNER jest opcjonalne, więc zwykłe JOIN oznacza to samo.

SELECT p.Imie, p.Pensja, d.NazwaDzialu
FROM Pracownicy AS p
INNER JOIN Dzialy AS d
    ON p.IdDzialu = d.IdDzialu;
ImiePensjaNazwaDzialu
Anna6500.00Sprzedaż
Marek9200.00IT
Ewa8700.00IT
Karolina7100.00Sprzedaż

Wynik ma 4 wiersze. Tomasza nie ma, bo nie ma działu, a HR-u nie ma, bo nie ma pracowników.

LEFT JOIN – wszystko z lewej tabeli

LEFT JOIN zwraca wszystkie wiersze z lewej tabeli (tej po FROM). Jeśli nie ma dla nich pary w prawej tabeli, kolumny prawej tabeli mają wartość NULL.

SELECT p.Imie, p.Pensja, d.NazwaDzialu
FROM Pracownicy AS p
LEFT JOIN Dzialy AS d
    ON p.IdDzialu = d.IdDzialu;
ImiePensjaNazwaDzialu
Anna6500.00Sprzedaż
Marek9200.00IT
Ewa8700.00IT
Tomasz5400.00NULL
Karolina7100.00Sprzedaż

Tym razem Tomasz jest na liście, z pustym działem.

Praktyczny trik: szukanie braków. Dodaj warunek IS NULL po prawej stronie, a dostaniesz tylko wiersze bez pary:

SELECT p.Imie
FROM Pracownicy AS p
LEFT JOIN Dzialy AS d
    ON p.IdDzialu = d.IdDzialu
WHERE d.IdDzialu IS NULL;

Wynik: Tomasz, czyli pracownik bez działu. Ten wzorzec przydaje się do wyszukiwania klientów bez zamówień, produktów bez sprzedaży czy rekordów bez powiązań.

RIGHT JOIN – wszystko z prawej tabeli

RIGHT JOIN to lustrzane odbicie LEFT JOIN: zwraca wszystkie wiersze z prawej tabeli, a dla braku pary w lewej wstawia NULL.

SELECT p.Imie, d.NazwaDzialu
FROM Pracownicy AS p
RIGHT JOIN Dzialy AS d
    ON p.IdDzialu = d.IdDzialu;
ImieNazwaDzialu
AnnaSprzedaż
MarekIT
EwaIT
KarolinaSprzedaż
NULLHR

Tomasza nie ma (nie ma działu), ale pojawił się dział HR bez pracownika. Kolejność wierszy może się różnić, jeśli nie użyjesz ORDER BY.

W praktyce RIGHT JOIN stosuje się rzadko. Ten sam wynik dostaniesz, zamieniając tabele miejscami i używając LEFT JOIN, co zwykle czyta się łatwiej.

FULL JOIN – wszystko z obu stron

FULL JOIN (pełna nazwa: FULL OUTER JOIN) zwraca wszystkie wiersze z obu tabel. Gdzie pary nie ma, po drugiej stronie pojawia się NULL.

SELECT p.Imie, d.NazwaDzialu
FROM Pracownicy AS p
FULL JOIN Dzialy AS d
    ON p.IdDzialu = d.IdDzialu;
ImieNazwaDzialu
AnnaSprzedaż
MarekIT
EwaIT
TomaszNULL
KarolinaSprzedaż
NULLHR

Wynik ma 6 wierszy: cztery pasujące, Tomasza bez działu i dział HR bez pracownika.

Podsumowanie: który JOIN zwraca ile wierszy

RodzajCo zwracaWierszy w naszym przykładzie
INNER JOINtylko pasujące pary4
LEFT JOINwszystko z lewej + pasujące z prawej5
RIGHT JOINwszystko z prawej + pasujące z lewej5
FULL JOINwszystko z obu tabel6

Jak wybrać w praktyce:

  • chcesz tylko dane, które mają powiązanie: INNER JOIN,
  • chcesz zachować wszystkie wiersze głównej tabeli: LEFT JOIN,
  • szukasz braków, czyli „kto nie ma…”: LEFT JOIN + IS NULL,
  • porównujesz dwie listy i chcesz zobaczyć rozbieżności po obu stronach: FULL JOIN.

Najczęstsze błędy przy JOIN

1. Warunek w WHERE zamienia LEFT JOIN w INNER JOIN. To najczęstsza pułapka. Spójrz na zapytanie:

SELECT p.Imie, d.NazwaDzialu
FROM Pracownicy AS p
LEFT JOIN Dzialy AS d
    ON p.IdDzialu = d.IdDzialu
WHERE d.NazwaDzialu = N'IT';

Chcieliśmy zachować wszystkich pracowników, ale wynik zawiera tylko Marka i Ewę. Wiersz Tomasza ma w d.NazwaDzialu wartość NULL, a NULL nie spełnia warunku w WHERE, więc zostaje odfiltrowany po połączeniu. Jeśli chcesz zachować wszystkich pracowników i dołączyć nazwę tylko dla działu IT, przenieś warunek do ON:

SELECT p.Imie, d.NazwaDzialu
FROM Pracownicy AS p
LEFT JOIN Dzialy AS d
    ON p.IdDzialu = d.IdDzialu
   AND d.NazwaDzialu = N'IT';

2. Brak warunku łączenia (iloczyn kartezjański). W starszej składni FROM Pracownicy, Dzialy bez warunku w WHERE każdy pracownik zostanie połączony z każdym działem: 5 × 3 = 15 wierszy. Przy dużych tabelach to potrafi zawiesić zapytanie. Używaj jawnego JOIN ... ON.

3. Powielone wiersze przy relacji jeden-do-wielu. Jeśli połączysz działy z pracownikami i zsumujesz coś z tabeli Dzialy (np. budżet działu), każdy dział zostanie policzony tyle razy, ilu ma pracowników. Wynik będzie zawyżony, choć zapytanie nie zgłosi żadnego błędu. Sumuj dane po stronie „jeden” przed połączeniem albo agreguj we właściwym miejscu. Więcej o agregacjach znajdziesz we wpisie o funkcjach agregujących w SQL.

4. NULL nie jest równy NULL. Dlatego Tomasz nie dopasował się do żadnego działu. Warunek NULL = NULL nie daje prawdy, więc wiersze z pustym kluczem nigdy nie tworzą pary w ON.

5. Niejednoznaczna nazwa kolumny. Jeśli obie tabele mają kolumnę o tej samej nazwie (u nas IdDzialu), a w SELECT podasz ją bez aliasu, SQL Server zgłosi błąd „Ambiguous column name”. Dlatego warto nadawać tabelom aliasy (p, d) i pisać p.IdDzialu.

6. Konflikt collation przy łączeniu kolumn tekstowych. Gdy łączysz tabele po kolumnach tekstowych z różnym ustawieniem collation, SQL Server zwróci komunikat „Cannot resolve the collation conflict”. Wyjaśniamy to w osobnym wpisie: co to jest collation w SQL Server.

Ćwicz na żywo

JOIN najlepiej opanować, pisząc zapytania samodzielnie. W naszych Laboratoriach SQL Serwer możesz ćwiczyć zapytania na żywo w przeglądarce, bez instalowania niczego. Spróbuj przepisać przykłady z tego wpisu i zmieniać rodzaje JOIN, żeby zobaczyć, jak zmienia się wynik.

Podsumowanie

JOIN SQL to fundament pracy z relacyjną bazą danych. Zapamiętaj trzy zasady: INNER JOIN zostawia tylko pasujące wiersze, LEFT JOIN zachowuje wszystko z lewej tabeli, a warunki dotyczące prawej tabeli w LEFT JOIN wpisuj do ON, nie do WHERE.

Chcesz nauczyć się łączenia tabel i pisania zapytań krok po kroku, na praktycznych ćwiczeniach? Sprawdź nasze szkolenie SQL Server dla początkujących. Program obejmuje m.in. łączenie tabel (połączenia wewnętrzne, lewo- i prawostronne), funkcje wbudowane i podzapytania.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Wymagane pola są oznaczone *

Przewijanie do góry