Jak działa CTE (WITH) w SQL? Najbardziej niedoceniana funkcja, która zmienia sposób pisania zapytań

kajodata.com 3 tygodni temu

Kiedy zaczynałem pracę z SQL-em, miałem dokładnie tę samą reakcję, którą ma większość osób uczących się baz danych: „Po co mi to kolejna rzecz? Przecież SELECT, JOIN i GROUP BY już działają.”
No właśnie — działają. Ale do czasu.

W pewnym momencie zaczynasz pisać coraz bardziej rozbudowane zapytania. Każdy SELECT ma w sobie kolejnego SELECT-a, który ma w sobie jeszcze jednego SELECT-a… i nagle patrzysz na kod, którego sam nie jesteś w stanie odczytać. A co dopiero wyjaśnić komuś innemu.

Wtedy właśnie pojawia się on — CTE, czyli Common Table Expression, a tak naprawdę komenda WITH, którą możesz potraktować jak sposób na „odłożenie” części logiki na bok, nadanie jej nazwy i ponowne użycie w dalszej części zapytania.

W tej lekcji pokażę ci, jak działają CTE, dlaczego są tak czytelne, jak je wykorzystuję w praktyce i jak dzięki nim zbudować wieloetapowe zapytanie, które mimo złożoności czyta się jak fragment prostego kodu. To wszystko na przykładzie realnego case’u biznesowego — dokładnie takiego, jaki możesz spotkać w pracy analityka danych.

H3: Od subquery do czytelnego kodu

Poprzednia lekcja w kursie dotyczyła subquery — czyli SELECT-ów umieszczanych wewnątrz innych SELECT-ów. To bardzo potężne narzędzie i możesz za jego pomocą zrobić naprawdę wiele: porównywać wartości z innymi wartościami, filtrować dane, generować agregaty, liczyć maksima, minima i wszystko, co tylko potrzebujesz.

Ale subquery mają jedną wadę: gdy kod zaczyna być większy, robi się po prostu nieczytelny.
I o ile czasem można to przeboleć — na przykład w szybkiej analizie robionej jednorazowo — to w pracy analityka często liczy się nie tylko efekt, ale też czytelność i możliwość utrzymania kodu.

Dlatego zamiast budować SELECT w SELECT-cie w SELECT-cie… wolę coś znacznie bardziej uporządkowanego — właśnie CTE.

H3: Czym jest CTE (Common Table Expression)?

CTE to tak naprawdę tabela tymczasowa utworzona „w locie”.
Nie istnieje w bazie fizycznie.
Istnieje tylko podczas wykonywania zapytania.

Budujesz ją w taki sposób:

WITH nazwa_tabeli AS ( SELECT ... FROM ... ) SELECT * FROM nazwa_tabeli;

Prawie jak subquery, ale o wiele czytelniej.

Możesz przygotować jedną taką tabelę, albo — jeżeli potrzebujesz — kilka na raz. Oddzielasz je przecinkami, a każda dostaje własną nazwę i własny SELECT.

Najważniejsze jest to, iż możesz w czytelny sposób rozbić problem na etapy.
To jest dokładnie ten moment, w którym osoba zaczynająca pracę z SQL-em mówi:
„Wow, dlaczego nikt mi tego wcześniej nie pokazał?”

Opanuj SQL z moim kursem!

Poznasz zarówno podstawy, jak i zaawansowane zapytania analityczne (CTE, subqueries, window functions). Nauczysz się pracować na różnych silnikach – na kursie pracujemy zarówno na MySQL, jak i na Postgres. Wszystko zainstalujemy na Twoim komputerze, plus dostaniesz mnóstwo zestawów danych do ćwiczeń.

H3: Budujemy pierwszy CTE – lista stanów

W naszym przykładzie biznesowym pracujemy na danych zamówień z różnych stanów USA.
Pierwszym krokiem będzie stworzenie listy wszystkich stanów.

W klasycznej wersji napisałbyś SELECT i po prostu z niego korzystał.
W wersji CTE robimy to tak:

WITH states AS ( SELECT DISTINCT State FROM Orders ) SELECT * FROM states;

Efekt?
Stworzyliśmy tabelę states, której możemy używać dalej — tak jak każdej innej tabeli.

Po uruchomieniu zapytania widzisz dokładnie wynik tej tabeli.
To jest pierwszy duży plus CTE: proces myślowy odzwierciedlony w kodzie.

H3: Dodajemy kolejne warstwy logiki

W analizie, którą wykonujemy, potrzebujemy trzech kluczowych zestawień:

  1. Liczby wszystkich zamówień w całej bazie
  2. Liczby zamówień per stan
  3. Liczby zamówień per stan i rodzaj wysyłki (shipping mode)

Każdą z tych rzeczy zrobimy jako osobne CTE.

Wszystkie zamówienia:

all_orders AS ( SELECT COUNT(*) AS total_orders FROM Orders )

Zamówienia per stan:

orders_per_state AS ( SELECT State, COUNT(*) AS state_orders FROM Orders GROUP BY State )

Zamówienia per stan i shipping mode:

orders_state_mode AS ( SELECT State, ShipMode, COUNT(*) AS orders_sm FROM Orders GROUP BY State, ShipMode )

A teraz uwaga:
Wszystkie te bloki budujemy jeden pod drugim.
Wygląda to czytelnie i opisowo — jak scenariusz analizy.

H3: Jak SQL wykonuje CTE?

Za każdym razem, gdy odpalasz zapytanie korzystające z CTE:

  1. Najpierw wykonywane są wszystkie zdefiniowane CTE
  2. Ich wyniki są trzymane w pamięci
  3. Zostają użyte w końcowym SELECT-cie

Co interesujące — nie musisz ich wszystkich później wykorzystywać.
Nawet jeżeli któreś CTE zdefiniujesz, ale nie dasz go w finalnym SELECT-cie, SQL i tak je policzy.

To ważne, bo pozwala ci tworzyć logiczne etapy pracy, choćby jeżeli część z nich ostatecznie nie będzie potrzebna.

H3: Ostatni SELECT – składamy całość w jeden wynik

Mamy wszystko, czego potrzebujemy.
Czas przejść do finalnego SELECT-a, w którym:

  • weźmiemy liczbę zamówień per stan i mode
  • połączymy ją z liczbą zamówień per stan
  • połączymy ją z liczbą zamówień globalnie
  • policzymy udział procentowy

Kod w uproszczonej formie (czytelnej pod WordPress):

WITH states AS (...), all_orders AS (...), orders_per_state AS (...), orders_state_mode AS (...) SELECT osm.State, osm.ShipMode, osm.orders_sm, ops.state_orders, ao.total_orders, ROUND(osm.orders_sm * 1.0 / ops.state_orders, 4) AS ratio_state, ROUND(osm.orders_sm * 1.0 / ao.total_orders, 4) AS ratio_global FROM orders_state_mode osm JOIN orders_per_state ops ON osm.State = ops.State CROSS JOIN all_orders ao WHERE osm.State IN ('California', 'Texas', 'New York') ORDER BY osm.State, osm.ShipMode;

I to jest właśnie piękno CTE:
Mimo iż logika analizy jest wieloetapowa, finalny SELECT jest krótki, logiczny, czytelny i spokojnie mieści się na jednym ekranie.

H3: Debugowanie błędów w SQL – kilka słów prawdy

W materiale, na bazie którego powstał ten artykuł, też pojawiały się błędy — brak nawiasu, brak słowa AS, drobne literówki.
Zostawiam je celowo.

Dlaczego?

Bo prawdziwa praca z SQL-em zawsze wiąże się z błędami.
Każdy analityk — choćby bardzo doświadczony — codziennie widzi przed sobą:

  • „Incorrect syntax near…”
  • „Column not found…”
  • „Ambiguous column name…”

To normalne.
Kluczowe jest nie to, żeby pisać zapytania bez błędów, ale żeby umieć je:

  • przeczytać
  • zrozumieć
  • poprawić

I właśnie CTE bardzo w tym pomagają.
Bo gdy masz logicznie rozbite etapy, debugowanie jest dużo prostsze.

H3: Dlaczego CTE robią taką różnicę w pracy analityka?

Z mojego doświadczenia mogę podać trzy główne powody.

1. Czytelność kodu

Duże zapytanie rozbite na mniejsze, nazwane etapy jest po prostu przyjemniejsze w pracy.

2. Logika analityczna przeniesiona do kodu

Możesz łatwo zobaczyć:

  • skąd pochodzą dane,
  • jak zostały przetworzone,
  • jaki jest przepływ informacji.

3. Łatwość modyfikacji

Chcesz zmienić logikę liczenia?
Grzebiesz w jednym CTE — reszta zostaje bez zmian.

4. Powtarzalne bloki

Możesz tworzyć z CTE gotowe „moduły” analityczne.
To ogromna różnica, gdy pracujesz przy raportach, dashboardach lub analizach ad-hoc.

H3: Case biznesowy – policzenie udziału zamówień

Cała analiza, którą budowaliśmy, miała na celu odpowiedzieć na pytanie:

„Jaki udział mają zamówienia różnych typów wysyłki w poszczególnych stanach?”

To jest bardzo typowe pytanie biznesowe.

Przykładowo:

  • jeśli w Kalifornii 60% zamówień to wysyłka First Class — to sygnał o profilu klientów
  • jeśli w Teksasie dominuje Standard Class — to zupełnie inny typ odbiorcy
  • jeśli globalnie jeden typ wysyłki rośnie szybciej — to wskazówka dla logistyki

Dzięki CTE mogliśmy:

  1. policzyć globalną liczbę zamówień
  2. policzyć liczbę zamówień per stan
  3. policzyć liczbę zamówień per stan i shipping mode
  4. spokojnie połączyć dane w jedną, logiczną strukturę
  5. policzyć udział procentowy

I co najważniejsze — cały kod jest czysty, logiczny i czytelny.

H3: CTE kontra subquery — kiedy czego używać?

Zawsze ktoś mnie o to pyta, więc odpowiem prosto:

Subquery są świetne, kiedy:

  • zapytanie jest krótkie
  • logika jest prosta
  • wartość pomocnicza jest potrzebna tylko raz

CTE są świetne, kiedy:

  • analiza ma kilka etapów
  • zapytanie zaczyna się rozrastać
  • chcesz mieć kod czytelny jak dokumentację
  • będziesz wracał do tego kodu za miesiąc (i musisz go zrozumieć)
  • pracujesz w zespole

Czyli w praktyce — w większości realnych przypadków.

H3: Drobna uwaga o wydajności

Czy CTE zawsze są szybsze?
Nie.
Czy są wolniejsze?
Też nie zawsze.

To zależy od bazy (PostgreSQL, SQL Server, BigQuery, Snowflake…), konfiguracji i optymalizatora.

W większości przypadków różnica jest marginalna, a czytelność kodu wygrywa.
W materiałach kursowych skupiam się przede wszystkim na tym, żeby dać ci narzędzia analityczne, które rozumiesz i których możesz użyć w pracy.

Optymalizacja SQL to osobny temat — i również jest w kursie omówiona.

Zapisz się do
newslettera

🎁 i zgarnij darmowe bonusy:

Poradnik Początkującego Analityka

Video - jak szukać pracy w IT

Regularne dawki darmowej wiedzy, bez spamu

Zgadzam się na przetwarzanie moich danych osobowych przez KajoData Kajo Rudziński w celu realizacji usługi newsletter, a tym samym wysyłania mi informacji o produktach blogowych, usługach, lub nowościach, zgodnie z polityką prywatności. Wiem, iż zgodę tę mogę w każdej chwili cofnąć.
Zapisuję się Loading...

Dzięki! To nie koniec...

...pamiętaj, by teraz wejść na maila i potwierdzić subskrybcję 🙂 Jeżeli nic nie doszło, to sprawdź skrzynkę ze spamem.
* * * Gdy potwierdzisz newsletter, dostaniesz ostateczne potwierdzenie i obiecane prezenty w kolejnym mailu 🙂

Zakończenie – podziel się tym artykułem

CTE to jedno z tych narzędzi, które nie robi spektakularnego pierwszego wrażenia, ale zmienia kompletnie sposób pisania zapytań.
Dzięki nim twoje analizy są:

  • bardziej czytelne
  • logicznie uporządkowane
  • łatwiejsze do debugowania
  • łatwiejsze do rozwijania

Jeśli dopiero zaczynasz pracę z SQL-em — ucząc się CTE robisz krok w stronę pisania zapytań na poziomie profesjonalnego analityka.
Jeśli już pracujesz w branży — prawdopodobnie po prostu uprościsz sobie życie.

Jeśli uważasz, iż ten artykuł może komuś pomóc, podziel się nim w swoich mediach społecznościowych.

Inne interesujące artykuły:

  • Jak działa FULL JOIN i SELF JOIN w SQL? Pełne wyjaśnienie na przykładach z życia analityka
  • Jak sprawdzam poprawność danych w Excelu: praktyczna lekcja z ISNUMBER i AND
  • Czekasz, aż poczujesz się gotowa do aplikowania? Ten moment może nie nadejść
  • Czujesz, iż jesteś 10 kroków za innymi? To tylko złudzenie
  • KajoDataSpace: najlepsze miejsce, żeby naprawdę wejść w świat analizy danych

Autorem artykułu jest Kajo Rudziński – analytical data architect, uznany ekspert w analizie danych, twórca KajoData oraz społeczności dla analityków KajoDataSpace.

To tyle w tym temacie. Analizujcie w pokoju!

Podobał Ci się ten artykuł 🙂?
Podziel się nim w Social Mediach 📱
>>> udostępnij go na LinkedIn i pokaż, iż codziennie uczysz się czegoś nowego
>>> wrzuć go na Facebooka, to się może przydać któremuś z Twoich znajomych
>>> Przypnij sobie tą stronkę to zakładek, może się przydać w przyszłości

Wolisz oglądać 📺 niż czytać – nie ma problemu
>>> Obserwuj i oglądaj KajoData na YouTube

Idź do oryginalnego materiału