Filtrowanie wyniku funkcji okienkowej
Dlaczego aby filtrować wynik funkcji okienkowej, trzeba umieścić ją w podzapytaniu lub CTE
Filtrowanie wyniku funkcji okienkowej 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.
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 windowUwagi 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
FROMzostanie odrzucone. - Wybierz funkcję rankingową odpowiednią do wymaganego sposobu obsługi remisów.
- Używaj
QUALIFYtylko 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.
QUALIFYto 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ą.
Ucz się SQL 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
- 30
- Lekcje
- 120
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 SQL Interview Prep, przejdź na CoddyKit PRO. Kurs SQL 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 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 „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 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
- OVER, PARTITION BY i ORDER BY
- ROW_NUMBER do unikatowej numeracji
- RANK a DENSE_RANK przy remisach
- Filtrowanie wyniku funkcji okienkowej