• Bazy danych i SQL
  • INNER JOIN w SQL: skąd biorą się brakujące i powielone wiersze?

INNER JOIN w SQL: skąd biorą się brakujące i powielone wiersze?

Radosław Krajewski • 11 listopada 2026
Diagramy zbiorów ilustrujące operacje INNER JOIN (część wspólna A i B) oraz różne typy OUTER JOIN (LEFT, RIGHT, FULL).

Spis treści

Raport zamówień w aplikacji .NET nagle pokazuje mniej klientów, niż widnieje w tabeli — choć zapytanie nie zgłasza błędu. INNER JOIN zwraca pary wierszy pasujące do warunku łączenia, ale wynik zależy też od tego, czy kolumna po drugiej stronie rzeczywiście identyfikuje pojedynczy rekord.

INNER JOIN pokazuje dopasowania, a szczegóły zależą od relacji między tabelami

  • Brak pary oznacza brak wiersza w wyniku złączenia wewnętrznego.
  • Wiele dopasowań tworzy wiele wierszy, nawet gdy klucz głównej tabeli jest unikalny.
  • ON opisuje powiązanie, a WHERE filtruje wynik zapytania.
  • Plan wykonania dobiera silnik bazy; nie wynika on bezpośrednio z nazwy złączenia w kodzie.

INNER JOIN zwraca tylko rekordy z dopasowaniem

Masz tabelę zamówień i tabelę klientów. Jeśli zamówienie wskazuje identyfikator klienta, który nie ma odpowiadającego wiersza w tabeli klientów, złączenie wewnętrzne pominie to zamówienie. Podobnie stanie się z klientem, który nie ma zamówień.

Warunek zapisujesz w klauzuli ON, a nazwy tabel skracasz aliasami. Jawna składnia ułatwia później odróżnienie relacji od dodatkowych filtrów:

SELECT
    o.Id AS OrderId,
    c.Name AS CustomerName
FROM Orders AS o
INNER JOIN Customers AS c
    ON c.Id = o.CustomerId;

Wynik zawiera kolumny wskazane w SELECT, ale tylko dla par, które spełniają warunek. Dokumentacja PostgreSQL opisuje tę regułę dla każdego wiersza lewej tabeli: do wyniku trafia wiersz za każde pasujące dopasowanie po prawej stronie. Jeśli dopasowań jest kilka, wynik też ma kilka wierszy.

Wybierz INNER JOIN albo LEFT JOIN według oczekiwanego wyniku

Decyzja zaczyna się od pytania biznesowego: czy raport ma pokazywać wyłącznie zamówienia z rozpoznanym klientem, czy wszystkie zamówienia, także osierocone? INNER JOIN pasuje do pierwszego warunku; gdy trzeba zachować każdy rekord z tabeli po lewej, użyj LEFT JOIN.

Sytuacja Skutek Co zrobić
Zamówienie bez pasującego klienta ma zniknąć z raportu Brak dopasowania eliminuje wiersz Użyj INNER JOIN
Raport ma pokazać każde zamówienie, również bez klienta Rekord zamówienia zostaje, a kolumny klienta będą puste (NULL) Użyj LEFT JOIN
Wynik ma zero wierszy, choć tabele zawierają dane Wartości w kolumnach łączenia mogą się nie zgadzać albo być puste Sprawdź identyfikatory i warunek ON osobno w obu tabelach
Wynik ma więcej wierszy niż zamówień Jeden rekord zamówienia pasuje do wielu wierszy po drugiej stronie Sprawdź unikalność kolumny łączenia i oczekiwaną krotność relacji

Możesz dodać warunek statusu do ON lub do WHERE, ale ich działanie nie zawsze będzie takie samo. W przypadku LEFT JOIN filtr w WHERE może odrzucić wiersze z pustymi kolumnami po prawej stronie, więc znikną rekordy, które miały pozostać. Jeśli chcesz zachować zamówienia bez klienta, sprawdź każdy filtr odnoszący się do tabeli klientów.

Trzy zamówienia i cztery zgłoszenia mogą dać dwanaście wierszy

Załóżmy, że jeden klient ma trzy zamówienia i cztery zgłoszenia do pomocy technicznej. Bezpośrednie połączenie tabel Orders i Tickets po identyfikatorze klienta wygeneruje dwanaście par: każde zamówienie połączy się z każdym zgłoszeniem tego klienta.

To nie błąd silnika SQL. Warunek opisuje relację klient-klient, więc każda para spełniająca go trafia do wyniku. Jeśli potem zsumujesz kwoty zamówień, każda kwota pojawi się przy każdym zgłoszeniu, a suma zostanie zawyżona.

Gdy potrzebujesz jednego wiersza na klienta z łączną wartością zamówień i liczbą zgłoszeń, najpierw zagreguj każdą tabelę osobno, a potem połącz wyniki:

WITH OrderTotals AS (
    SELECT CustomerId, SUM(Total) AS OrderTotal
    FROM Orders
    GROUP BY CustomerId
),
TicketCounts AS (
    SELECT CustomerId, COUNT(*) AS TicketCount
    FROM Tickets
    GROUP BY CustomerId
)
SELECT
    o.CustomerId,
    o.OrderTotal,
    t.TicketCount
FROM OrderTotals AS o
INNER JOIN TicketCounts AS t
    ON t.CustomerId = o.CustomerId;

Takie zapytanie pokazuje klientów, którzy mają jednocześnie zamówienie i zgłoszenie. Gdy raport ma zachować również klientów występujących tylko w jednej z tych tabel, trzeba zmienić rodzaj złączenia albo połączyć obie listy osobnym wzorcem. Najpierw ustal, co ma oznaczać jeden wiersz raportu, a dopiero potem dobierz relacje.

INNER JOIN w kodzie nie określa algorytmu wykonania

Dwa zapytania z takim samym warunkiem mogą być wykonane przez silnik różnymi metodami. W SQL Server Nested Loops, Merge Join i Hash Join to operatory fizyczne wybierane przez optymalizator; zapis INNER JOIN określa logikę wyniku, a nie konkretny algorytm.

W dokumentacji Microsoft Learn opisano, że wybór zależy między innymi od rozmiaru danych, dostępnych indeksów i ich rozkładu. Przy czytaniu planu wykonania zwróć uwagę, czy operator dopasowuje mały zestaw przez indeks, scala posortowane dane, czy buduje strukturę haszującą dla wejść bez odpowiedniego uporządkowania. Nie wymuszaj operatora tylko dlatego, że jego nazwa brzmi szybciej; najpierw porównaj plan szacowany z rzeczywistymi liczbami wierszy.

W kodzie aplikacji, na przykład w zapytaniu wykonywanym przez Entity Framework, analizuj także wygenerowany SQL. Abstrakcja LINQ może wyglądać prosto, ale to warunek relacji oraz plan bazy rozstrzygają, które rekordy wrócą i jak silnik do nich dotrze.

Zanim uznasz brakujące wiersze za błąd danych

Gdy wynik jest mniejszy od oczekiwań, zacznij od sprawdzenia kilku konkretnych rekordów z obu tabel: czy identyfikatory po obu stronach są równe, czy typy kolumn są zgodne i czy warunek nie łączy przypadkiem danych po nazwie zamiast po kluczu. INNER JOIN wiernie realizuje podane dopasowanie, nawet jeśli samo dopasowanie nie odpowiada intencji raportu.

Ja stawiam na jawne warunki ON i świadomie określam, co ma oznaczać pojedynczy wiersz wyniku. Dzięki temu łatwiej odróżnić brak relacji od powielonych danych, a raport z aplikacji nie zaskakuje ani pustą listą, ani zawyżoną sumą.

FAQ - Najczęstsze pytania

INNER JOIN zwraca tylko wiersze, dla których warunek z klauzuli ON znajduje dopasowanie po obu stronach. Jeśli identyfikator klienta z zamówienia nie odpowiada żadnemu wierszowi w tabeli klientów, zamówienie nie pojawi się w wyniku. Sprawdź wartości identyfikatorów, typy kolumn i sam warunek łączenia.

Użyj LEFT JOIN, jeśli tabela zamówień jest po lewej stronie złączenia. Zachowa on każde zamówienie, a kolumny klienta dla niedopasowanych wierszy będą miały wartość NULL. Uważaj na filtry dotyczące klientów w WHERE, bo mogą odrzucić te wiersze; sprawdź, czy taki filtr nie powinien znaleźć się w ON.

Jeśli klient ma trzy zamówienia i cztery zgłoszenia, połączenie obu tabel po identyfikatorze klienta tworzy dwanaście par. Każda kwota zamówienia może wtedy wystąpić przy każdym zgłoszeniu, co zawyża sumę. Najpierw zsumuj zamówienia i policz zgłoszenia osobno dla każdego klienta, a potem połącz zagregowane wyniki.

Nie. INNER JOIN określa, które dopasowane wiersze mają znaleźć się w wyniku, a silnik wybiera fizyczną metodę wykonania. W SQL Server może to być Nested Loops, Merge Join lub Hash Join; wybór zależy między innymi od rozmiaru danych i dostępnych indeksów. Oceniając wydajność, porównaj szacowane i rzeczywiste liczby wierszy w planie wykonania.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

left join
inner join
agregacja sql
plany wykonania
Autor Radosław Krajewski
Radosław Krajewski
Nazywam się Radosław Krajewski i od 6 lat zgłębiam tajniki programowania .NET, chmury Azure oraz sztucznej inteligencji. Moja przygoda z tymi technologiami zaczęła się od fascynacji tym, jak złożone problemy można rozwiązywać za pomocą kodu i innowacyjnych narzędzi. Staram się przekazywać tę wiedzę w sposób zrozumiały, dzieląc się swoimi doświadczeniami i spostrzeżeniami na kursdotnet.pl. W moich artykułach skupiam się na praktycznych aspektach, porównuję różne rozwiązania i analizuję najnowsze trendy, aby dostarczyć Wam rzetelne i aktualne informacje, które pomogą Wam rozwijać się w tej dynamicznie zmieniającej się dziedzinie.

Udostępnij artykuł

Napisz komentarz