Przejdź do głównej treści
eLearner.app
Moduł 7 · Lekcja 1 z 425/57 w kursie~12 min
Lekcje modułu (1/4)

CTE: zapytania wieloetapowe z WITH

Prawdziwe zapytania mają tendencję do wzrostu: trzy JOIN, GROUP BY, podzapytanie, kolejne podzapytanie… i stają się nieczytelne. CTE („Wspólna tabela Wyrażenia”, klauzula WITH) pozwalają nadać nazwę obiektowi krok pośredni i użyj go tak, jakby był tabelą w głównym zapytaniu.

Podstawowa składnia

SQL
WITH nome_cte AS (
  SELECT-- query interna
)
SELECT-- query principale, usa nome_cte come fosse una tabella
FROM   nome_cte;

CTE jest ważny tylko dla następującego po nim zapytania: nie przetrwa egzekucja.

Przykład

Znajdź 3 klientów, którzy wydali najwięcej (suma ponad zrealizowane zamówienia):

SQL
WITH total_spent AS (
  SELECT o.customer_id,
         SUM(oi.quantity * oi.unit_price) AS total
  FROM   orders      o
  JOIN   order_items oi ON oi.order_id = o.id
  WHERE  o.status = 'delivered'
  GROUP BY o.customer_id
)
SELECT c.email,
       s.total
FROM   total_spent s
JOIN   customers c ON c.id = s.customer_id
ORDER BY s.total DESC
LIMIT  3;

Przeczytaj po angielsku: ”najpierw oblicz wydatki na klienta, a następnie dołącz do klientów i zdobądź pierwsze 3". Bez CTE potrzebowałbyś inline podzapytanie w FROM (legalne, ale głośniejsze).

Wiele CTE w kaskadzie

Można zdefiniować wiele CTE oddzielonych przecinkami, a każdy z nich może się odnosić do poprzednich:

SQL
WITH total_spent AS (
  SELECT customer_id, SUM(quantity * unit_price) AS total
  FROM   order_items oi
  JOIN   orders      o ON oi.order_id = o.id
  WHERE  o.status = 'delivered'
  GROUP BY customer_id
),
average AS (
  SELECT AVG(total) AS total_average
  FROM   total_spent
)
SELECT c.email, s.total
FROM   total_spent s
JOIN   customers c ON c.id = s.customer_id
CROSS JOIN average
WHERE  s.total > average.total_average
ORDER BY s.total DESC;

CROSS JOIN average, ponieważ average zawsze ma jeden wiersz: Iloczyn kartezjański po prostu dołącza total_average do każdego wiersza wyniku.

CTE a podzapytanie: kiedy którego użyć

CTE świecą, gdy:

  • to samo podzapytanie zostało użyte dwa lub więcej razy w zapytaniu głównym;
  • chcesz wyraźnie określić strukturę w nazwanych krokach (samodokumentowanie);
  • warunkiem dla rekursywnych CTE (WITH RECURSIVE, następna lekcja w tym module).

Podzapytanie wbudowane jest bardziej zwięzłe w przypadku kroku użytego tylko raz.

Spróbuj

Ćwiczenie#sql.m7.l1.e1
Próby: 0Ładowanie...

Użyj współczynnika CTE o nazwie „total_spent”, który oblicza dla każdego klienta całkowite wydatki (SUM(ilość * cena_jednostkowa)) na dostarczone zamówienia. Następnie w głównym zapytaniu pokaż adres e-mail i sumę dla 3 osób, które najwięcej wydają. Sortuj według sumy malejącej, z ograniczeniem do 3.

Ładowanie edytora...
Pokaż wskazówkę

Wewnątrz sumy CTE ilość * cena_jednostkowa. W głównym zapytaniu DOŁĄCZ do klientów o identyfikatorze.

Rozwiązanie dostępne po 3 próbach

Przejrzyj ćwiczenie

Ćwiczenie#sql.m7.l1.e2
Próby: 0Ładowanie...

Taki sam CTE „całkowity wydatek” jak w poprzednim ćwiczeniu. W głównym zapytaniu pokaż adres e-mail i sumę dla klientów, których wydatki przekraczają średnie wydatki (wśród wszystkich klientów z co najmniej jednym dostarczonym zamówieniem). Sortuj według sumy malejącej.

Ładowanie edytora...
Pokaż wskazówkę

Podzapytanie skalarne w WHERE: SELECT AVG(total) FROM total_spent.

Rozwiązanie dostępne po 3 próbach