0Pricing
SQL Interview Prep · Урок

Объединение нескольких CTE в цепочку

Создавайте последовательность именованных шагов, ссылающихся друг на друга.

«Объединение нескольких CTE в цепочку» — бесплатный урок SQL Interview Prep на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения SQL Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс SQL Interview Prep содержит 4 уроков всего.

Зачем объединять CTE в цепочку

Реальные задачи на собеседованиях редко укладываются в один шаг. Объединение CTE в цепочку позволяет построить конвейер именованных этапов, в котором каждый этап преобразует результат предыдущего. Это отражает подход опытного инженера, который разбивает сложный запрос на управляемые части.

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

Синтаксис с разделением запятыми

Чтобы определить несколько CTE, один раз напишите WITH, а затем разделите каждый именованный блок запятой. Не повторяйте ключевое слово WITH.

  • Один WITH в начале.
  • Запятая между определениями CTE.
  • Нет запятой перед итоговым основным запросом.
WITH a AS (
    SELECT customer_id FROM orders
),
b AS (
    SELECT customer_id FROM a
)
SELECT *
FROM b;

Последующие CTE могут ссылаться на предыдущие

В этом заключается преимущество цепочек: CTE может читать данные из любого CTE, определённого до него. Такая видимость только вперёд позволяет строить цепочку зависимостей.

Предыдущий CTE не может видеть последующий, поэтому порядок имеет значение. Располагайте этапы от исходных данных к итоговой форме.

WITH filtered AS (
    SELECT *
    FROM events
    WHERE event_type = 'purchase'
),
per_user AS (
    SELECT user_id, COUNT(*) AS purchases
    FROM filtered
    GROUP BY user_id
)
SELECT *
FROM per_user;

Разбор примера: конвейер из трёх этапов

Вопрос: какова средняя сумма расходов среди клиентов, потративших более 1000 долларов? Разбейте задачу на три этапа: общие расходы каждого клиента, отбор клиентов с большими расходами, затем вычисление среднего значения.

Имя каждого CTE описывает его назначение, поэтому проверяющий сразу понимает ход выполнения.

WITH spend AS (
    SELECT customer_id, SUM(amount) AS total
    FROM orders
    GROUP BY customer_id
),
big_spenders AS (
    SELECT customer_id, total
    FROM spend
    WHERE total > 1000
)
SELECT AVG(total) AS avg_big_spend
FROM big_spenders;

Порядок определения имеет значение

Поскольку видимость действует только вперёд, CTE, зависящий от другого CTE, должен быть указан после своей зависимости. Если Вы ссылаетесь на имя, которое ещё не определено, база данных выдаёт ошибку «отношение не существует».

Полезная привычка: читайте список CTE сверху вниз и проверяйте, что каждое используемое имя уже встречалось выше.

Ссылка на один CTE из нескольких других

Один CTE может служить источником для нескольких последующих CTE. В этом цепочки превосходят вложенные подзапросы: Вы вычисляете базовый результат один раз и создаёте на его основе несколько ветвей.

Здесь и active, и recent читают данные из base, что позволяет избежать дублирования логики.

WITH base AS (
    SELECT * FROM users WHERE deleted = false
),
active AS (
    SELECT id FROM base WHERE last_login > NOW() - INTERVAL '7 days'
),
recent AS (
    SELECT id FROM base WHERE created_at > NOW() - INTERVAL '30 days'
)
SELECT (SELECT COUNT(*) FROM active) AS active_cnt,
       (SELECT COUNT(*) FROM recent) AS recent_cnt;

Объединение двух CTE

Связанные в цепочку CTE часто объединяются в основном запросе. Вычислите каждую сторону отдельно, а затем объедините их. Так каждая вычислительная часть остаётся изолированной, а соединение получается простым.

Ниже мы независимо вычисляем количество заказов и количество возвратов, а затем объединяем эти данные для каждого клиента.

WITH orders_cte AS (
    SELECT customer_id, COUNT(*) AS orders
    FROM orders GROUP BY customer_id
),
refunds_cte AS (
    SELECT customer_id, COUNT(*) AS refunds
    FROM refunds GROUP BY customer_id
)
SELECT o.customer_id, o.orders, COALESCE(r.refunds, 0) AS refunds
FROM orders_cte o
LEFT JOIN refunds_cte r ON r.customer_id = o.customer_id;

Читаемость вместо вложенности

Сравните подзапрос, вложенный на три уровня, с конвейером из трёх CTE. Вложенная версия заставляет читателя мысленно разворачивать запрос изнутри наружу. Версия с CTE читается в порядке выполнения — сверху вниз.

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

Распространённая ошибка при объединении в цепочку

Начинающие разработчики часто ставят запятую после последнего CTE, прямо перед основным SELECT. Такая завершающая запятая приводит к синтаксической ошибке.

  • Запятые ставятся только между определениями CTE.
  • После последней закрывающей скобки сразу идёт основной запрос, без запятой.

Ещё одна ловушка: забыть, что каждый CTE должен содержать свой полностью завершённый SELECT внутри скобок.

Выполняется ли каждый этап отдельно

Важный нюанс для собеседования: логически конвейер выглядит как последовательность отдельных шагов, но оптимизатор может встроить их и объединить в единый план выполнения. В большинстве СУБД Вам не обязательно платить за материализацию промежуточных результатов.

Таким образом, объединение в цепочку помогает Вам рассуждать о запросе, не обязательно ухудшая производительность. Упомяните это, чтобы показать глубину понимания.

Имена этапов как элементы конвейера

Хорошие имена этапов превращают запрос в самодокументируемый код. Предпочитайте имена, описывающие выходные данные каждого шага, а не выполняемую операцию.

  • spend и big_spenders лучше, чем step1 и step2.
  • Читатель должен понимать весь ход выполнения только по именам CTE.
  • Единообразные имена этапов делают соединение в основном запросе очевидным.

На собеседовании чёткие имена этапов показывают, что Вы пишете удобный для сопровождения рабочий код.

Быстрая проверка

Проверьте, насколько хорошо Вы понимаете, как связанные в цепочку CTE ссылаются друг на друга.

Повторение: объединение CTE в цепочку

Вы научились строить конвейеры: один WITH, определения CTE, разделённые запятыми, и видимость только вперёд, при которой каждый этап может читать данные предыдущих этапов.

  • Распределяйте CTE от исходных данных к итоговому результату.
  • Повторно используйте базовый CTE в нескольких последующих шагах.
  • Не ставьте завершающую запятую перед основным запросом.
  • Объединение в цепочку повышает читаемость, не обязательно ухудшая производительность.

Далее: сравнение CTE, подзапросов и временных таблиц.

Часто задаваемые вопросы

Урок «Объединение нескольких CTE в цепочку» бесплатный?

Да — полный текст урока «Объединение нескольких CTE в цепочку» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс SQL Interview Prep, подпишись на CoddyKit PRO. Курс SQL Interview Prep содержит 4 уроков всего.

Чему я научусь в уроке «Объединение нескольких CTE в цепочку»?

Создавайте последовательность именованных шагов, ссылающихся друг на друга. Ты практикуешь SQL Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать SQL Interview Prep?

Предыдущий опыт не требуется. SQL Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Объединение нескольких CTE в цепочку»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке SQL Interview Prep?

Да. Каждый урок SQL Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Написание первого CTE
  2. Объединение нескольких CTE в цепочку
  3. CTE, подзапрос или временная таблица
  4. Преобразование вложенных запросов в CTE
← Назад к SQL Interview Prep