> Что такое общее табличное выражение (CTE) в SQL (Go)

Уровень: junior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Ютека

Стек: C# /.NET, Go

> Пример ответа

Короткий ответ

Общее табличное выражение (CTE) - это именованный временный результирующий набор, определённый в начале SQL-запроса с помощью ключевого слова WITH. Он существует только на время выполнения одного запроса и позволяет разбить сложную логику на читаемые блоки. CTE не создаёт постоянную таблицу и не сохраняется в базе данных после завершения запроса.

Подробное объяснение

CTE объявляется через WITH имя_выражения AS (подзапрос) и далее используется в основном запросе как обычная таблица или view. В отличие от подзапросов, CTE можно ссылаться несколько раз в одном запросе, что упрощает переиспользование логики. Некоторые СУБД поддерживают рекурсивные CTE через WITH RECURSIVE, которые позволяют обходить иерархии (например, дерево категорий или организационную структуру). Важно понимать, что CTE не материализуется автоматически: оптимизатор может встроить его в основной запрос или вычислить отдельно в зависимости от СУБД и версии. В PostgreSQL до версии 12 CTE всегда материализовался, что влияло на производительность. В C#/.NET при работе через Entity Framework Core CTE часто пишут вручную через FromSqlRaw, так как LINQ не всегда генерирует WITH. В Go с database/sql или pgx CTE используется как обычный SQL-текст.

На практике

CTE применяют для пошаговой обработки данных: сначала отфильтровать, потом агрегировать, потом соединить. Это делает запрос линейным и читаемым сверху вниз. Также CTE удобны для замены временных таблиц, когда не нужна индексация или сохранение между запросами. В рекурсивных CTE решают задачи обхода графов и деревьев без написания циклов на стороне приложения. При этом стоит помнить, что в некоторых СУБД (например, MySQL до 8.0) CTE отсутствовали, а в SQL Server рекурсивные CTE имеют ограничение на глубину рекурсии по умолчанию 100.

Пример кода

SQL
WITH monthly_sales AS (
SELECT
customer_id,
DATE_TRUNC('month', order_date) AS month,
SUM(amount) AS total
FROM orders
GROUP BY customer_id, DATE_TRUNC('month', order_date)
)
SELECT
customer_id,
month,
total,
AVG(total) OVER (PARTITION BY customer_id) AS avg_monthly
FROM monthly_sales
WHERE total > 1000;

Как отвечать на собеседовании

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

Что проверяет интервьюер

Понимание разницы между CTE, подзапросом, временной таблицей и view. Знание синтаксиса WITH и умение применять его на практике. Осведомлённость о рекурсивных CTE и их ограничениях. Понимание, что CTE не является физическим объектом в базе. Способность объяснить trade-off между читаемостью и производительностью.

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

Путать CTE с временной таблицей и считать, что он сохраняется между запросами. Думать, что CTE всегда материализуется и ускоряет запрос. Забывать, что в рекурсивном CTE нужен базовый случай и условие остановки. Использовать CTE там, где достаточно простого подзапроса, усложняя код без выгоды. Ожидать поддержки CTE во всех СУБД без проверки версии.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью