Coding Interview Prep · Lekcja

Filtrowanie wyniku funkcji okienkowej

Dlaczego aby filtrować wynik funkcji okienkowej, trzeba umieścić ją w podzapytaniu lub CTE

Lekcja 4 z 413 kroki

Filtrowanie wyniku funkcji okienkowej to bezpłatna lekcja Coding 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 Coding Interview Prep, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Coding Interview Prep zawiera 4 lekcji w sumie.

Dlaczego nie można filtrować funkcji okna w WHERE

Częsty „haczyk” na rozmowach rekrutacyjnych: zapisanie WHERE ROW_NUMBER() OVER (...) = 1 powoduje błąd. Funkcji okna nie wolno używać w WHERE, GROUP BY ani HAVING.

Powodem jest logiczna kolejność wykonywania. WHERE wybiera wiersze przed obliczeniem funkcji okna. Okno nie zostało jeszcze nawet obliczone, więc nie można odwołać się do niego w filtrze.

Wyjaśnienie kolejności wykonywania

Funkcje okna są obliczane w osobnej fazie, która następuje po FROM, WHERE, GROUP BY i HAVING, ale przed końcowymi ORDER BY i LIMIT.

W chwili wykonywania WHERE ranking ani numer wiersza jeszcze nie istnieją. Aby je filtrować, należy najpierw pozwolić na zakończenie obliczeń funkcji okna, a następnie odfiltrować utworzoną kolumnę w zewnętrznej warstwie zapytania.

Wzorzec opakowania w podzapytaniu

Standardowe rozwiązanie polega na obliczeniu funkcji okna w zapytaniu wewnętrznym (tabeli pochodnej), nadaniu wynikowi aliasu, a następnie odfiltrowaniu tego aliasu w zewnętrznym WHERE.

Tabela pochodna musi mieć alias (tutaj t) — rekruterzy zwracają uwagę na kandydatów, którzy o nim zapominają. Teraz rn jest zwykłą kolumną, z którą zapytanie zewnętrzne może porównać wartość.

SELECT *
FROM (
  SELECT
    name, department, salary,
    ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn
  FROM employees
) t
WHERE rn = 1;

Wzorzec CTE (często czytelniejszy)

Common Table Expression wykonuje to samo zadanie, zapewniając czytelniejszą strukturę. Ranking definiuje się w kroku WITH, a następnie filtruje w głównym zapytaniu.

Funkcjonalnie jest to identyczne z podzapytaniem, ale podczas programowania na żywo rekruterzy zwykle preferują CTE, ponieważ intencja jest czytelna od góry do dołu.

WITH ranked AS (
  SELECT
    name, department, salary,
    ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn
  FROM employees
)
SELECT name, department, salary
FROM ranked
WHERE rn = 1;

Przykład: N najlepszych wyników w grupie

Najczęstszy problem dotyczący funkcji okna: „3 najlepiej zarabiających pracowników w każdym dziale”. Ranking należy obliczyć w CTE, a następnie zachować na zewnątrz wiersze spełniające warunek rn <= 3.

Funkcję rankingową należy wybrać zgodnie z obsługą remisów: ROW_NUMBER ogranicza wynik do dokładnie 3 wierszy na dział; jeśli remisy na granicy mają zostać uwzględnione, należy użyć RANK/DENSE_RANK.

WITH ranked AS (
  SELECT department, name, salary,
         ROW_NUMBER() OVER (
           PARTITION BY department ORDER BY salary DESC
         ) AS rn
  FROM employees
)
SELECT department, name, salary
FROM ranked
WHERE rn <= 3
ORDER BY department, rn;

Przykład: filtrowanie sumy narastającej

Wzorzec opakowania nie służy wyłącznie do rankingów. Każdy wynik funkcji okna — sumy narastające, średnie kroczące, różnice obliczane za pomocą LAG — należy filtrować w ten sam sposób.

W tym przykładzie obliczamy saldo narastająco, a następnie zachowujemy tylko te wiersze, w których po raz pierwszy przekroczyło ono 1000. Filtr znajduje się poza warstwą funkcji okna.

WITH balances AS (
  SELECT
    account_id, txn_date, amount,
    SUM(amount) OVER (
      PARTITION BY account_id ORDER BY txn_date
    ) AS running_balance
  FROM transactions
)
SELECT *
FROM balances
WHERE running_balance > 1000;

QUALIFY: skrót dostępny w niektórych bazach danych

Snowflake, BigQuery, Teradata i DuckDB udostępniają klauzulę QUALIFY, która filtruje wyniki funkcji okna bezpośrednio — bez potrzeby stosowania opakowania. Jest wykonywana po funkcjach okna, czyli dokładnie w miejscu, którego potrzebujemy.

Warto wspomnieć o QUALIFY, aby pokazać znajomość różnych rozwiązań, ale należy zaznaczyć, że nie jest to element standardu SQL i nie występuje w PostgreSQL, MySQL ani SQL Server, gdzie nadal potrzebne jest podzapytanie lub CTE.

-- Snowflake / BigQuery only:
SELECT department, name, salary
FROM employees
QUALIFY ROW_NUMBER() OVER (
  PARTITION BY department ORDER BY salary DESC
) = 1;

Nie należy mylić HAVING z filtrowaniem funkcji okna

Kandydaci czasami próbują użyć HAVING do filtrowania rankingu. HAVING filtruje grupy po agregacji wykonanej przez GROUP BY i nadal jest wykonywane przed funkcjami okna, więc również nie może odwoływać się do kolumny funkcji okna.

  • WHERE → filtruje wiersze przed grupowaniem i przed funkcjami okna.
  • HAVING → filtruje zagregowane grupy, nadal przed funkcjami okna.
  • Filtrowanie funkcji okna → wymaga zapytania zewnętrznego (lub QUALIFY).

Łączenie wstępnego filtra z filtrem funkcji okna

Często filtruje się dane zarówno przed obliczeniem funkcji okna, jak i po nim. Zwykłe filtry wierszy należy zastosować w wewnętrznym WHERE (dzięki temu funkcja okna widzi tylko istotne wiersze), a następnie odfiltrować wynik funkcji okna w zapytaniu zewnętrznym.

W tym przykładzie najpierw ograniczamy dane do aktywnych pracowników, a następnie wybieramy najlepiej zarabiającą osobę w każdym dziale spośród nich. Umieszczenie WHERE active wewnątrz zmienia zbiór wierszy poddawanych rankingowi.

WITH ranked AS (
  SELECT department, name, salary,
         ROW_NUMBER() OVER (
           PARTITION BY department ORDER BY salary DESC
         ) AS rn
  FROM employees
  WHERE is_active = true        -- pre-filter before ranking
)
SELECT * FROM ranked
WHERE rn = 1;                   -- post-filter on the window

Uwagi dotyczące wydajności

Rekruterzy mogą zapytać, czy opakowanie wpływa negatywnie na wydajność. Zwykle nie: optymalizator traktuje podzapytanie lub CTE jako część jednego planu i oblicza funkcję okna tylko raz. Samo opakowanie nie powoduje dodatkowego skanowania.

Jest jednak pewne zastrzeżenie: w niektórych silnikach CTE może stanowić barierę optymalizacji (być materializowane), dlatego w najbardziej obciążonych ścieżkach tabela pochodna lub QUALIFY może zapewnić lepszy plan. Jeśli ma to znaczenie, należy sprawdzić plan za pomocą EXPLAIN.

Typowe błędy

Końcowa lista kontrolna:

  • Nigdy nie umieszczaj funkcji okna w WHERE/HAVING — powoduje to błąd.
  • Zawsze nadaj alias tabeli pochodnej; nienazwane podzapytanie w FROM zostanie odrzucone.
  • Wybierz funkcję rankingową odpowiednią do wymaganego sposobu obsługi remisów.
  • Używaj QUALIFY tylko tam, gdzie jest obsługiwane; w pozostałych przypadkach zastosuj CTE lub opakowanie w podzapytaniu.

Szybkie sprawdzenie

Dlaczego filtrowanie funkcji okna wymaga opakowania?

Podsumowanie: filtrowanie wyników funkcji okna

Ma Pan/Pani już pełny obraz rankingu za pomocą funkcji okna:

  • Funkcje okna są wykonywane po WHERE/GROUP BY/HAVING, dlatego nie można ich tam filtrować.
  • Należy opakować funkcję okna w podzapytanie lub CTE (zawsze z aliasem), a następnie filtrować wynik w zapytaniu zewnętrznym.
  • Umożliwia to wybieranie N najlepszych wyników w grupie, najnowszego wiersza dla klucza oraz progów sum narastających.
  • QUALIFY to wygodny, niestandardowy skrót dostępny tylko w Snowflake/BigQuery.

Ma Pan/Pani teraz kompletny zestaw narzędzi do rankingu, który rekruterzy najczęściej sprawdzają.

Bezpłatny start

Ucz się Coding Interview Prep dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
90
Lekcje
360

Często zadawane pytania

Czy lekcja „Filtrowanie wyniku funkcji okienkowej” jest bezpłatna?

Tak — pełny tekst „Filtrowanie wyniku funkcji okienkowej” 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 Coding Interview Prep, przejdź na CoddyKit PRO. Kurs Coding Interview Prep zawiera 4 lekcji w sumie.

Co nauczysz się w „Filtrowanie wyniku funkcji okienkowej”?

Dlaczego aby filtrować wynik funkcji okienkowej, trzeba umieścić ją w podzapytaniu lub CTE Ćwiczysz Coding 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ąć Coding Interview Prep?

Nie wymagamy żadnego doświadczenia. Coding 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 „Filtrowanie wyniku funkcji okienkowej”?

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 Coding Interview Prep?

Tak. Każda lekcja Coding 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. OVER, PARTITION BY i ORDER BY
  2. ROW_NUMBER do unikatowej numeracji
  3. RANK a DENSE_RANK przy remisach
  4. Filtrowanie wyniku funkcji okienkowej
← Powrót do Coding Interview Prep