УРОК 17 / 27· ≈ 30 мин

Общие табличные выражения (WITH / CTE)

CTE — именованный подзапрос

CTE (Common Table Expression, «обобщённое табличное выражение») — это временный именованный результат, объявленный через WITH перед основным запросом. По сути это тот же подзапрос, но вынесенный наверх и названный — так сложные запросы читаются гораздо легче.

WITH seat_counts AS (
  SELECT airplane_code, COUNT(*) AS seats
  FROM seats
  GROUP BY airplane_code
)
SELECT airplane_code, seats
FROM seat_counts
WHERE seats > 200
ORDER BY seats DESC;

Логически мы сначала описываем seat_counts (число мест по самолётам), а основной запрос обращается к нему как к таблице. Физический порядок выбирает оптимизатор: PostgreSQL может встроить обычный CTE в основной запрос или материализовать его, поэтому WITH сам по себе не гарантирует отдельного первого вычисления.

Чем CTE удобнее обычного подзапроса

  • логика читается сверху вниз: сначала «заготовка», потом основной запрос;
  • на один CTE можно ссылаться несколько раз;
  • можно объявить несколько CTE через запятую и строить их друг на друге.
WITH a AS ( ... ),
     b AS ( ... берёт данные из a ... )
SELECT ... FROM b;

Внутри основного запроса к CTE применимо всё, что мы уже знаем: WHERE, JOIN, ORDER BY, и даже вложенный подзапрос (например, сравнение со средним по самому CTE).

Разбор: как строить запрос из CTE по шагам

CTE удобно писать «снизу вверх». Сначала напишите и запустите первый шаг отдельно:

SELECT airplane_code, COUNT(*) AS routes
FROM routes
GROUP BY airplane_code;

Когда результат правильный, заверните его в WITH rc AS (…) и напишите следующий шаг, который берёт данные из rc. Так каждый кусок проверен до того, как на нём построено что-то ещё.

Типичные ошибки

  • Второе слово WITH. Несколько CTE перечисляются через запятую после одного WITH: WITH a AS (…), b AS (…).
  • Точка с запятой после CTE. WITH a AS (…); SELECT … — ошибка: точка с запятой закончила запрос раньше времени.
  • Обращение к CTE из другого запроса. CTE существует только внутри своего запроса. В следующем запросе его уже нет.
💡 CTE не делает запрос «умнее» подзапроса — он делает его понятнее. Для сложных отчётов это огромная помощь. (Существует ещё WITH RECURSIVE для иерархий — это уже за рамками базового курса.)

Практика

8
  1. Тест 1 — Как правильно объявить два CTE в одном запросе?
  2. Тест 2 — Где можно обращаться к CTE, объявленному через WITH?
  3. Задача 1 — Первый CTE: быстрые самолёты
  4. Задача 2 — Самолёты с 200+ местами (CTE + агрегат)
  5. Задача 3 — Маршруты по моделям через CTE
  6. Задача 4 — Средняя выручка рейса
  7. Задача 5 — Топ аэропортов вылета (CTE + JOIN)
  8. Задача 6 — Цепочка из двух CTE

Задачи решаются прямо здесь, в браузере, на учебной базе — нужна только бесплатная регистрация, чтобы сохранялись ответы и прогресс.

Зарегистрироваться и решитьВойти

Потренируйтесь в тренажёре

6

Задачи на ту же тему, но на другой базе — продажи магазина электроники. Хороший способ проверить, что тема понятна, а не просто запомнилась на примерах урока.

Все задачи тренажёра →
ПодзапросыСледующий урок: UNION, EXISTS и NOT EXISTS