0Pricing
SQL Interview Prep · Lekcja

Pułapka WHERE w złączeniu zewnętrznym

Dlaczego filtrowanie kolumny ze złączenia zewnętrznego w WHERE po cichu zmienia je w złączenie wewnętrzne

Pułapka WHERE w złączeniu zewnętrznym to bezpłatna lekcja SQL Interview Prep na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej SQL Interview Prep, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs SQL Interview Prep zawiera 4 lekcji w sumie.

Pułapka, w którą wpadają prawie wszyscy

To najczęstszy błąd dotyczący złączeń zewnętrznych, celowo wykorzystywany przez osoby prowadzące rozmowy rekrutacyjne: „Pokaż każdego klienta i jego zamówienia z 2024 roku, uwzględniając klientów bez zamówień z 2024 roku”.

Kandydat używa LEFT JOIN, a następnie dodaje filtr daty w WHERE, przez co klienci bez zamówień z 2024 roku po cichu znikają. LEFT JOIN niepostrzeżenie staje się INNER JOIN. Zrozumienie przyczyny jest oznaką doświadczenia na poziomie seniora.

Błędne zapytanie

Oto błąd. Zapis wygląda rozsądnie: zachować wszystkich klientów, połączyć ich zamówienia i ograniczyć wynik do 2024 roku.

Jednak klienci bez zamówień lub bez zamówień z 2024 roku znikają z wyniku. Wymóg uwzględnienia ich nie zostaje spełniony.

-- BUG: drops customers with no 2024 order
SELECT c.name, o.id, o.order_date
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.order_date >= '2024-01-01';

Dlaczego to nie działa

Proszę przypomnieć sobie kolejność operacji: najpierw wykonywane jest JOIN, które tworzy wiersze, w których niedopasowani klienci mają NULL we wszystkich kolumnach zamówień. Następnie wykonywane jest WHERE.

W przypadku niedopasowanego klienta o.order_date ma wartość NULL, więc wyrażenie o.order_date >= '2024-01-01' przyjmuje wartość UNKNOWN, a nie TRUE. WHERE zachowuje tylko wiersze, dla których wynik jest TRUE, dlatego wiersze z NULL zostają odfiltrowane — dokładnie te, które LEFT JOIN miał zachować.

NULL unieważnia filtr

Każde porównanie z NULL daje wynik UNKNOWN: NULL >= '2024-01-01' daje UNKNOWN, NULL = 5 daje UNKNOWN, a nawet NULL <> 5 daje UNKNOWN.

Ponieważ WHERE przepuszcza tylko wiersze, dla których wyrażenie ma wartość TRUE, każdy zachowany wiersz bez dopasowania zostaje odrzucony. Cały sens złączenia zewnętrznego zostaje zniweczony przez pojedynczy predykat WHERE dotyczący kolumny prawej tabeli.

Rozwiązanie: filtr w ON

Należy przenieść filtr do klauzuli ON. Wtedy staje się on częścią warunku dopasowania i jest stosowany przed zachowaniem wierszy, dzięki czemu niedopasowani klienci nadal pozostają w wyniku z wartościami NULL.

-- CORRECT: filter lives in ON
SELECT c.name, o.id, o.order_date
FROM customers c
LEFT JOIN orders o
  ON o.customer_id = c.id
  AND o.order_date >= '2024-01-01';
-- customers with no 2024 order: kept, NULL order

ON a WHERE w jednym zdaniu

Oto zasada, którą warto powtórzyć podczas rozmowy:

W przypadku zachowywanej (zewnętrznej) tabeli warunki dotyczące drugiej tabeli należy umieszczać w ON, a warunki dotyczące samej zachowywanej tabeli — w WHERE.

  • ON decyduje, co jest uznawane za dopasowanie (jest wykonywane podczas złączenia).
  • WHERE filtruje końcowe wiersze (jest wykonywane później i usuwa wiersze z wartościami NULL).

Wyniki obok siebie

Te same dane, dwa miejsca umieszczenia filtra i różne odpowiedzi. Załóżmy, że Carol nie ma zamówienia z 2024 roku.

  • Filtr w WHERE: Carol znika. W praktyce jest to złączenie wewnętrzne.
  • Filtr w ON: Carol pojawia się raz z wartościami NULL w kolumnach zamówienia, więc wymaganie zostaje spełnione.

Różnica w wyniku jest istotą tej pułapki.

-- ON version output
-- Alice | 50 | 2024-03-01
-- Bob   | 20 | 2024-05-02
-- Carol | NULL | NULL   <-- preserved

Kiedy WHERE jest rzeczywiście poprawne

Nie każde użycie WHERE przy złączeniu zewnętrznym jest błędem. Filtrowanie zachowywanej tabeli jest poprawne — nie dotyczy wartości NULL pochodzących ze złączenia.

Złączenie antysemi z poprzedniej lekcji celowo używa WHERE o.id IS NULL, aby wykorzystać właśnie to zachowanie. Umiejętność polega na rozpoznaniu, z którym przypadkiem ma się do czynienia.

-- Fine: filtering the preserved (left) table
SELECT c.name, o.id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE c.country = 'US';

Heurystyka wykrywania problemu

Podczas przeglądania złączenia zewnętrznego należy sprawdzić klauzulę WHERE pod kątem predykatów dotyczących niezachowywanej tabeli (z wyjątkiem testów IS NULL używanych w złączeniach antysemi).

Jeśli w WHERE widzą Państwo o.someColumn = ... albo test zakresu lub równości po stronie zewnętrznej, należy podejrzewać tę pułapkę. Proszę zadać sobie pytanie: „Czy to zmienia moje LEFT JOIN w INNER JOIN?” Zwykle tak.

Wiele warunków

Można połączyć oba sposoby umieszczania warunków. Warunki dopasowania dotyczące prawej tabeli należy umieścić w ON, a rzeczywisty filtr wykonywany po złączeniu, dotyczący lewej tabeli, w WHERE. Oba warunki mogą współistnieć bez problemu.

SELECT c.name, o.id, o.amount
FROM customers c
LEFT JOIN orders o
  ON o.customer_id = c.id
  AND o.amount > 100          -- match condition
WHERE c.signup_year = 2023;    -- preserved-table filter

Jak to wyjaśnić na głos

Podczas rozmowy należy opisać mechanizm, a nie tylko podać poprawkę:

„Najpierw wykonywane jest złączenie, które uzupełnia kolumny prawej tabeli wartościami NULL w niedopasowanych wierszach. Predykat WHERE dotyczący tych kolumn przyjmuje dla wierszy z NULL wartość UNKNOWN, a WHERE odrzuca wiersze, dla których wynik nie jest TRUE, więc złączenie zewnętrzne zmienia się w wewnętrzne. Umieszczenie predykatu w ON zachowuje go jako warunek dopasowania i pozwala zachować niedopasowane wiersze”. Takie wyjaśnienie sprawdza się za każdym razem.

Szybkie sprawdzenie

Należy wyświetlić wszystkich klientów i tylko ich zamówienia z 2024 roku, zachowując również klientów, którzy nie mieli żadnego takiego zamówienia.

Podsumowanie

Filtrowanie kolumny niezachowywanej tabeli w WHERE po cichu zmienia złączenie zewnętrzne w wewnętrzne, ponieważ wartości NULL z niedopasowanych wierszy nie spełniają predykatu (dają UNKNOWN), a WHERE je odrzuca.

  • Warunki dopasowania dotyczące tabeli zewnętrznej należy umieszczać w ON.
  • Filtry dotyczące zachowywanej tabeli należy umieszczać w WHERE.
  • IS NULL w WHERE oznacza celowe złączenie antysemi, a nie tę pułapkę.
  • Należy wyjaśnić kolejność operacji, aby pokazać pełne zrozumienie tematu.

Często zadawane pytania

Czy lekcja „Pułapka WHERE w złączeniu zewnętrznym” jest bezpłatna?

Tak — pełny tekst „Pułapka WHERE w złączeniu zewnętrznym” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu SQL Interview Prep, przejdź na CoddyKit PRO. Kurs SQL Interview Prep zawiera 4 lekcji w sumie.

Co nauczysz się w „Pułapka WHERE w złączeniu zewnętrznym”?

Dlaczego filtrowanie kolumny ze złączenia zewnętrznego w WHERE po cichu zmienia je w złączenie wewnętrzne Ćwiczysz SQL Interview Prep z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć SQL Interview Prep?

Nie wymagamy żadnego doświadczenia. SQL Interview Prep w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Pułapka WHERE w złączeniu zewnętrznym”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji SQL Interview Prep?

Tak. Każda lekcja SQL Interview Prep zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. LEFT JOIN i zachowywanie niedopasowanych wierszy
  2. Semantyka RIGHT i FULL OUTER JOIN
  3. Znajdowanie wierszy bez dopasowania (anti-join)
  4. Pułapka WHERE w złączeniu zewnętrznym
← Powrót do SQL Interview Prep