RIGHT JOIN w SQL - jak działa i kiedy użyć LEFT JOIN

Diagram porównuje RIGHT JOIN i LEFT JOIN, pokazując, że dają ten sam wynik.

Napisano przez

Tymoteusz Sobczak

Opublikowano

11 paź 2026

Spis treści

Gdy chcesz pokazać wszystkie rekordy z jednej tabeli, nawet wtedy, gdy druga nie ma dla nich dopasowania, zwykły INNER JOIN nie wystarczy. Właśnie wtedy przydaje się RIGHT JOIN, czyli prawe złączenie zewnętrzne. Poniżej pokazuję, jak działa, jak pisać takie zapytania, gdzie pojawia się wartość NULL oraz kiedy lepiej odwrócić kolejność tabel i użyć LEFT JOIN.

Najważniejsze zasady działania prawego złączenia w SQL

  • Wszystkie wiersze z prawej tabeli pozostają w wyniku, nawet bez dopasowania.
  • Brak powiązanego rekordu po lewej stronie jest oznaczany przez NULL.
  • Warunek łączenia zapisuje się najczęściej po słowie ON.
  • RIGHT OUTER JOIN i RIGHT JOIN oznaczają tę samą operację.
  • W praktyce często czytelniej odwrócić tabele i użyć LEFT JOIN.

Czym jest prawe złączenie i jakie wiersze zwraca

Prawe złączenie zewnętrzne zachowuje każdy wiersz z tabeli zapisanej po prawej stronie JOIN. Dołącza do niego dane z lewej tabeli, ale tylko wtedy, gdy warunek łączenia znajdzie pasujący rekord.

Jeżeli dopasowania nie ma, kolumny pochodzące z lewej tabeli przyjmują wartość NULL. To nie jest błąd ani pusty tekst. NULL oznacza, że dla konkretnego wiersza nie znaleziono odpowiedniej wartości.

Przykładowo możemy połączyć tabelę pracowników z tabelą działów. Jeżeli po prawej stronie umieścimy działy, wynik pokaże również te działy, w których nie pracuje obecnie żadna osoba. Przy połączeniu wewnętrznym takie rekordy zostałyby pominięte.

Określenia „lewa” i „prawa” odnoszą się wyłącznie do kolejności tabel w zapytaniu. Tabela po słowie FROM jest lewa, a tabela występująca po słowie JOIN jest prawa. To właśnie druga z nich ma zostać zachowana w całości.

Jak napisać zapytanie z RIGHT OUTER JOIN

Podstawowa składnia wygląda następująco:

SELECT kolumny
FROM tabela_lewa
RIGHT OUTER JOIN tabela_prawa
    ON tabela_lewa.klucz = tabela_prawa.klucz;

Słowo OUTER można pominąć, ponieważ w tym przypadku jest opcjonalne. Obie formy wykonują to samo prawe złączenie. Ja zwykle używam krótszego zapisu, a pełną wersję zostawiam w kodzie, gdy chcę szczególnie mocno podkreślić typ operacji.

Najważniejsza część zapytania znajduje się po ON. To tam wskazujemy, które kolumny opisują relację między tabelami. Najczęściej jest to klucz główny jednej tabeli i klucz obcy drugiej, ale warunek może też obejmować kilka kolumn albo dodatkowe ograniczenia.

SELECT
    p.imie,
    p.nazwisko,
    d.nazwa AS dzial
FROM pracownicy AS p
RIGHT OUTER JOIN dzialy AS d
    ON p.dzial_id = d.id;

W tym przykładzie tabela dzialy znajduje się po prawej stronie. Dlatego wynik zawiera wszystkie działy. Jeżeli dział nie ma przypisanego pracownika, pola imie i nazwisko będą miały wartość NULL.

Praktyczny przykład z działami i pracownikami

Załóżmy, że dane wyglądają tak:

pracownicy dzialy
Anna, dział 1 Sprzedaż, id 1
Piotr, dział 2 IT, id 2
brak rekordu Marketing, id 3

Zapytanie z prawym złączeniem zwróci także dział Marketing, mimo że nie ma on przypisanego pracownika. Rezultat może wyglądać tak:

imie nazwisko dzial
Anna Kowalska Sprzedaż
Piotr Nowak IT
NULL NULL Marketing

Ten wzorzec przydaje się przy raportach, w których trzeba pokazać pełną listę jednostek nadrzędnych, nawet jeśli część z nich nie ma jeszcze danych podrzędnych. Spotykam go między innymi przy zestawieniach działów, kategorii produktów, kursów bez zapisanych uczestników oraz lokalizacji bez przypisanych punktów.

Dobrze działa również przy agregowaniu danych. Jeżeli chcemy policzyć produkty w każdej kategorii, także w tych pustych, możemy napisać:

SELECT
    k.nazwa,
    COUNT(p.id) AS liczba_produktow
FROM produkty AS p
RIGHT OUTER JOIN kategorie AS k
    ON p.kategoria_id = k.id
GROUP BY k.id, k.nazwa;

W tym przypadku celowo użyłem COUNT(p.id), a nie COUNT(*). Dla kategorii bez produktu SQL nadal utworzy jeden wiersz z wartościami NULL po lewej stronie, dlatego COUNT(*) zwróciłby 1, choć faktycznie produktów nie ma. Liczenie konkretnej kolumny z lewej tabeli zwróci poprawne zero.

RIGHT JOIN a LEFT JOIN i INNER JOIN

Najłatwiej zrozumieć prawe złączenie, porównując je z innymi podstawowymi rodzajami JOIN. Różnica nie dotyczy tylko składni. Decyduje o tym, które rekordy mają przetrwać brak dopasowania.

Rodzaj złączenia Co zachowuje Typowe zastosowanie
INNER JOIN Wyłącznie rekordy pasujące po obu stronach Lista pracowników mających przypisany dział
LEFT JOIN Wszystkie rekordy z lewej tabeli Wszyscy klienci, także bez zamówień
RIGHT OUTER JOIN Wszystkie rekordy z prawej tabeli Wszystkie kategorie, także bez produktów
FULL OUTER JOIN Wszystkie rekordy z obu tabel Porównanie dwóch kompletnych zbiorów danych

Prawe złączenie jest logicznym odpowiednikiem lewego złączenia po zamianie kolejności tabel. Te dwa zapytania zwrócą ten sam zestaw powiązań:

SELECT *
FROM pracownicy AS p
RIGHT OUTER JOIN dzialy AS d
    ON p.dzial_id = d.id;
SELECT *
FROM dzialy AS d
LEFT JOIN pracownicy AS p
    ON p.dzial_id = d.id;

W codziennej pracy częściej wybieram LEFT JOIN, ponieważ wiele zapytań czyta się wtedy od głównego zbioru danych do jego uzupełnienia. Nie oznacza to jednak, że prawe złączenie jest gorsze. Ma sens, gdy istniejące zapytanie ma już ustaloną kolejność tabel albo gdy zachowanie prawej tabeli lepiej opisuje intencję raportu.

Najczęstsze błędy przy prawym złączeniu

Pomylenie prawej tabeli

Najczęstsza pomyłka polega na założeniu, że „prawa” tabela to ta ważniejsza biznesowo. SQL nie zna takiej reguły. Liczy się wyłącznie tabela stojąca po słowie JOIN, dlatego przed uruchomieniem zapytania sprawdzam, czy właśnie ona ma być zachowana w całości.

Filtrowanie NULL w klauzuli WHERE

Dużo problemów powoduje filtr umieszczony w niewłaściwym miejscu. Takie zapytanie:

SELECT d.nazwa, p.imie
FROM pracownicy AS p
RIGHT OUTER JOIN dzialy AS d
    ON p.dzial_id = d.id
WHERE p.aktywny = 1;

usunie działy bez pracowników, ponieważ dla nich p.aktywny ma wartość NULL. W praktyce prawe złączenie zacznie zachowywać się podobnie do połączenia wewnętrznego. Jeżeli chcemy zachować wszystkie działy i pobrać tylko aktywnych pracowników, warunek trzeba przenieść do ON:

SELECT d.nazwa, p.imie
FROM pracownicy AS p
RIGHT OUTER JOIN dzialy AS d
    ON p.dzial_id = d.id
   AND p.aktywny = 1;

To drobna zmiana, ale ma duży wpływ na wynik. Warunki w ON ograniczają dopasowanie, natomiast warunki w WHERE filtrują już gotowy rezultat.

Niepoprawne klucze i duplikaty

Jeżeli łączone kolumny nie są kluczami o oczekiwanej unikalności, jeden rekord może połączyć się z wieloma innymi. W efekcie liczba wierszy wzrośnie, a raport może wyglądać tak, jakby dane zostały powielone. Przed użyciem JOIN sprawdzam, czy relacja jest typu jeden do jednego, jeden do wielu czy może przypadkiem wiele do wielu.

Przeczytaj również: SQL Self Join - Jak łączyć tabelę z samą sobą?

Brak indeksów przy dużych tabelach

Sam wybór prawego albo lewego złączenia nie gwarantuje lepszej wydajności. Przy większych zbiorach znaczenie mają przede wszystkim indeksy na kolumnach używanych w ON, selektywność filtrów oraz plan wykonania zapytania. Warto też unikać SELECT *, gdy raport potrzebuje tylko kilku kolumn.

Kiedy odwrócić tabele i użyć LEFT JOIN

Jeśli możesz swobodnie zaprojektować zapytanie od początku, lewy wariant często będzie bardziej czytelny. Zamiast myśleć „zachowaj prawą tabelę”, zaczynasz od tabeli, która ma być kompletna, i zapisujesz ją po FROM. Dla wielu osób taki układ jest po prostu łatwiejszy do czytania.

Przykład z kategoriami można zapisać tak:

SELECT
    k.nazwa,
    COUNT(p.id) AS liczba_produktow
FROM kategorie AS k
LEFT JOIN produkty AS p
    ON p.kategoria_id = k.id
GROUP BY k.id, k.nazwa;

Rezultat będzie równoważny wersji z prawym złączeniem, ale intencja jest od razu widoczna. Tabela kategorii jest głównym zbiorem, a produkty są tylko danymi uzupełniającymi. Wybór LEFT JOIN zamiast RIGHT JOIN jest najczęściej decyzją o czytelności, a nie o możliwościach SQL.

Prawe złączenie zostawiłbym wtedy, gdy jego zapis naturalnie pasuje do istniejącego zapytania albo gdy modyfikacja kolejności wielu połączonych tabel zwiększyłaby ryzyko błędu. W rozbudowanych raportach każda zmiana układu może wpłynąć na aliasy, kolejność kolumn i dodatkowe warunki, więc nie zawsze opłaca się przepisywać działający kod tylko dla preferowanego stylu.

Co sprawdzić przed uruchomieniem prawego złączenia

Najpierw wskaż tabelę, której wszystkie rekordy muszą znaleźć się w wyniku. Potem upewnij się, że stoi ona po prawej stronie JOIN, a warunek w ON łączy właściwe klucze. Na końcu sprawdź, czy filtry w WHERE nie usuwają przypadkiem wierszy zawierających NULL.

Jeśli wynik ma pokazywać elementy bez dopasowania, przetestuj osobno co najmniej jeden taki przypadek. To najlepszy sposób, aby szybko wykryć pomylone strony złączenia, niepoprawny warunek albo użycie COUNT(*) zamiast liczenia konkretnej kolumny.

Najprostsza zasada brzmi więc tak: zachowaj po prawej stronie to, czego nie wolno zgubić. Jeżeli taki zapis utrudnia czytanie zapytania, odwróć tabele i użyj LEFT JOIN. Obie drogi prowadzą do tego samego typu wyniku, o ile świadomie kontrolujesz kolejność tabel, wartości NULL i miejsce stosowania filtrów.

FAQ - Najczęstsze pytania

RIGHT JOIN zachowuje wszystkie wiersze z tabeli zapisanej po słowie JOIN, czyli z prawej strony. Gdy nie ma dopasowania w lewej tabeli, jej kolumny otrzymują wartość NULL.

Nie różnią się działaniem. Słowo OUTER jest opcjonalne, dlatego oba zapisy wykonują prawe złączenie zewnętrzne. Ten sam wynik można zwykle uzyskać, zamieniając kolejność tabel i używając LEFT JOIN.

Dla kategorii bez produktów złączenie nadal tworzy jeden wiersz, ale kolumny produktu mają wartość NULL. COUNT(*) policzyłby taki wiersz jako 1, natomiast COUNT(p.id) pominie wartość NULL i zwróci poprawne zero.

Jeśli chcesz zachować wszystkie rekordy z prawej tabeli, warunek dotyczący lewej tabeli umieść w klauzuli ON. Filtr w WHERE, na przykład p.aktywny = 1, odrzuci wiersze z NULL i może sprawić, że zapytanie zacznie działać podobnie do INNER JOIN.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi:

sql złączenia null agregacja

Udostępnij artykuł

Tymoteusz Sobczak

Tymoteusz Sobczak

Nazywam się Tymoteusz Sobczak i od 7 lat zajmuję się programowaniem webowym. Moje zainteresowanie tą dziedziną zaczęło się od prostych projektów, które realizowałem w wolnym czasie. Z czasem odkryłem, jak fascynujące jest tworzenie aplikacji, które mogą ułatwiać życie innym. Chętnie dzielę się swoją wiedzą, pomagając czytelnikom zrozumieć złożone zagadnienia związane z programowaniem, od podstawowych technik po bardziej zaawansowane rozwiązania. Pisząc na temat programowania, staram się dostarczać informacje, które są nie tylko użyteczne, ale także zrozumiałe. Zawsze dokładam starań, aby moje źródła były wiarygodne, a treści aktualne. Lubię upraszczać trudne tematy i organizować wiedzę w sposób, który ułatwia naukę. Wierzę, że każdy, kto ma chęci, może stać się dobrym programistą, a ja jestem tutaj, aby wskazać drogę.

Napisz komentarz