Czy Twoje zapytania SQL stają się coraz dłuższe, bardziej skomplikowane i trudne do odczytania? Masz wrażenie, że proste GROUP BY i złączenia (JOIN) to za mało, aby sprostać analitycznym wyzwaniom? Jeśli tak, to ten artykuł jest dla Ciebie! Poznaj Funkcje Okna (Window Functions) oraz CTE (Common Table Expressions) – dwa potężne narzędzia, które odmienią Twój sposób pisania zapytań SQL.
W tym wpisie przeprowadzimy Cię od podstawowych koncepcji do zaawansowanych przykładów, pokazując, jak te funkcje mogą uprościć Twoją pracę i otworzyć nowe możliwości analityczne.
🎯 Część 1: Czym są i dlaczego warto używać CTE (Common Table Expressions)?
Wyobraź sobie, że piszesz bardzo złożone zapytanie z wieloma podzapytaniami. Szybko staje się ono nieczytelne i trudne w utrzymaniu. Tu z pomocą przychodzą CTE!
Common Table Expression to nic innego jak tymczasowy, nazwany zbiór wyników, do którego możesz odwoływać się w kolejnych częściach zapytania (SELECT, INSERT, UPDATE lub DELETE). Można o nim myśleć jak o jednorazowej, inteligentnej tabeli tymczasowej lub widoku.
Kluczowe zalety CTE:
- Czytelność: Dzielą skomplikowane zapytania na logiczne, łatwe do zrozumienia kroki.
- Wielokrotne użycie: Możesz wielokrotnie odwoływać się do tego samego CTE w jednym zapytaniu.
- Rekurencja: Umożliwiają pisanie zapytań rekurencyjnych, co jest idealne do pracy z danymi hierarchicznymi (np. struktury organizacyjne, drzewa kategorii).
Składnia CTE
Składnia jest prosta. Zaczynamy od słowa kluczowego WITH, nadajemy nazwę naszemu CTE, a następnie definiujemy zapytanie w nawiasach.
SQL
WITH MojeCTE AS (
-- Tutaj umieszczasz zapytanie SELECT, które tworzy tymczasowy zbiór wyników
SELECT klient_id, SUM(wartosc_zamowienia) AS laczna_wartosc
FROM zamowienia
GROUP BY klient_id
)
-- Teraz możesz użyć "MojeCTE" jak zwykłej tabeli
SELECT *
FROM MojeCTE
WHERE laczna_wartosc > 1000;
CTE a podzapytania
Choć podobne, CTE często przewyższają podzapytania czytelnością. Porównajmy:
SQL
-- Z użyciem podzapytania (mniej czytelne)
SELECT *
FROM (
SELECT klient_id, SUM(wartosc_zamowienia) AS laczna_wartosc
FROM zamowienia
GROUP BY klient_id
) AS sprzedaz_klientow
WHERE laczna_wartosc > 1000;
W przypadku wielu kroków pośrednich, zagnieżdżone podzapytania stają się koszmarem. CTE pozwalają na ich sekwencyjne i płaskie ułożenie.
윈 Część 2: Magia Funkcji Okna
Funkcje okna to prawdziwy przełom w analitycznym SQL. Pozwalają one na wykonywanie obliczeń na zbiorze wierszy (nazywanym “oknem” lub “partycją”), które są w jakiś sposób powiązane z bieżącym wierszem.
W przeciwieństwie do GROUP BY, które agreguje wiersze do jednego rekordu, funkcje okna zwracają wartość dla każdego wiersza, zachowując oryginalną liczbę rekordów.
Składnia Funkcji Okna
Kluczem do funkcji okna jest klauzula OVER().
SQL
NAZWA_FUNKCJI() OVER (
PARTITION BY kolumna1, kolumna2 -- Dzieli wiersze na "okna" (partycje). To jest opcjonalne.
ORDER BY kolumna3 -- Sortuje wiersze wewnątrz każdej partycji.
-- ROWS/RANGE ... (opcjonalne, definiuje ramkę wewnątrz partycji)
)
PARTITION BY: Działa podobnie doGROUP BY, ale nie zwija wierszy. Tworzy partycje, w ramach których funkcja jest liczona niezależnie.ORDER BY: Określa kolejność wierszy w partycji, co jest kluczowe dla funkcji rankingowych (ROW_NUMBER,RANK) oraz porównawczych (LAG,LEAD).
Popularne Funkcje Okna
- Ranking:
ROW_NUMBER(),RANK(),DENSE_RANK()- Idealne do tworzenia rankingów, np. “top 3 najlepiej sprzedających się produktów w każdej kategorii”.
SELECT nazwa_produktu, kategoria, sprzedaz, ROW_NUMBER() OVER(PARTITION BY kategoria ORDER BY sprzedaz DESC) as ranking_w_kategorii FROM sprzedaz_produktow; - Porównawcze:
LAG()iLEAD()LAG()daje dostęp do wartości z poprzedniego wiersza w partycji.LEAD()daje dostęp do wartości z następnego wiersza.- Świetne do obliczania różnic, np. porównania sprzedaży z poprzednim miesiącem.
SELECT miesiac, sprzedaz, LAG(sprzedaz, 1, 0) OVER(ORDER BY miesiac) as sprzedaz_poprzedni_miesiac FROM sprzedaz_miesieczna; - Agregujące:
SUM(),AVG(),COUNT()- Mogą działać jak funkcje okna, np. do obliczenia sumy kroczącej lub procentowego udziału w kategorii.
SELECT pracownik, dzial, pensja, SUM(pensja) OVER(PARTITION BY dzial) as suma_pensji_w_dziale FROM pracownicy;
🤝 Część 3: Połączenie Mocy – CTE i Funkcje Okna razem
Prawdziwa siła tych narzędzi ujawnia się, gdy używamy ich razem. CTE mogą posłużyć do przygotowania i oczyszczenia danych, a następnie na tymczasowym zbiorze wyników możemy zastosować funkcje okna do skomplikowanych analiz.
Przykład: Znajdźmy pracowników w każdym dziale, którzy zarabiają więcej niż średnia w swoim dziale.
SQL
WITH DanePracownikow AS (
SELECT
imie,
nazwisko,
dzial,
pensja,
-- Krok 1: Oblicz średnią pensję dla każdego działu za pomocą funkcji okna
AVG(pensja) OVER (PARTITION BY dzial) AS srednia_pensja_w_dziale
FROM pracownicy
)
-- Krok 2: Użyj CTE do prostej filtracji
SELECT
imie,
nazwisko,
dzial,
pensja,
srednia_pensja_w_dziale
FROM DanePracownikow
WHERE pensja > srednia_pensja_w_dziale;
Dzięki takiemu podejściu zapytanie jest niezwykle czytelne: najpierw przygotowujemy dane (obliczamy średnią), a potem je filtrujemy.
⚡ Część 4: Wydajność i Dobre Praktyki
- Indeksuj! Wydajność funkcji okna drastycznie wzrasta, jeśli kolumny użyte w
PARTITION BYiORDER BYsą zaindeksowane. - Filtruj wcześnie: Zawsze staraj się ograniczyć zbiór danych za pomocą klauzuli
WHEREprzed zastosowaniem skomplikowanych operacji. - CTE a wydajność: W niektórych systemach baz danych (np. starszych wersjach PostgreSQL), CTE mogą działać jak “bariery optymalizacyjne”, co czasem pomaga, a czasem szkodzi. Warto testować wydajność w porównaniu z podzapytaniami. Nowoczesne bazy danych zazwyczaj radzą sobie z tym znacznie lepiej.
- Różnice między bazami danych: Chociaż składnia jest w dużej mierze spójna, istnieją drobne różnice w implementacji i dostępnych funkcjach między systemami takimi jak PostgreSQL, SQL Server, MySQL czy Oracle. Zawsze warto sprawdzić dokumentację swojej bazy danych.
Podsumowanie
Opanowanie Common Table Expressions i funkcji okna to krok milowy w rozwoju umiejętności SQL. Pozwalają one pisać czystsze, bardziej czytelne i znacznie potężniejsze zapytania analityczne. Zamiast męczyć się z zagnieżdżonymi podzapytaniami i skomplikowanymi złączeniami, możesz tworzyć eleganckie i wydajne rozwiązania.
Nie bój się eksperymentować! Zacznij od prostych rankingów i sum kroczących, a szybko odkryjesz, jak wiele problemów, które wydawały się trudne, staje się prostszych z odpowiednimi narzędziami.
Źródła
- Oficjalna dokumentacja PostgreSQL dotycząca zapytań
WITH(CTE). - Oficjalna dokumentacja PostgreSQL dotycząca funkcji okna.
- Oficjalna dokumentacja Microsoft SQL Server dotycząca
WITH common_table_expression. - Oficjalna dokumentacja Microsoft SQL Server dotycząca klauzuli
OVER. - Oficjalna dokumentacja MySQL 8.0 dotycząca
WITH(Common Table Expressions). - Oficjalna dokumentacja MySQL 8.0 dotycząca funkcji okna.
- Artykuł “SQL Window Functions and CTEs” na portalu Medium.
- Artykuł “CTE vs Subquery in SQL” na portalu Geekflare.
- Tutorial “CTEs and Window Functions” na stronie Crunchy Data.