Теория· 10 мин· 10 XP
Синтаксис WITH: пишем первый CTE
Базовый синтаксис
sql
WITH имя_cte AS (
SELECT ...
FROM ...
WHERE ...
)
SELECT *
FROM имя_cte;
Ключевые правила:
WITHстоит передSELECT- После
ASидут скобки с подзапросом - Основной запрос идёт после закрывающей скобки — без
WITH - После основного запроса нет точки с запятой внутри CTE
Пример: клиенты с активными счетами
Без CTE:
sql
SELECT c.first_name, c.last_name, a.account_type
FROM clients c
JOIN (SELECT id, client_id, account_type FROM accounts WHERE balance > 0) a
ON a.client_id = c.id
ORDER BY c.last_name;
С CTE:
sql
WITH active_accounts AS (
SELECT id, client_id, account_type
FROM accounts
WHERE balance > 0
)
SELECT c.first_name, c.last_name, a.account_type
FROM clients c
JOIN active_accounts a ON a.client_id = c.id
ORDER BY c.last_name;
Второй вариант читается как текст: «сначала берём активные счета, потом соединяем их с клиентами».
Несколько CTE через запятую
sql
WITH
cte1 AS (
SELECT ...
),
cte2 AS (
SELECT ...
FROM cte1 -- можно ссылаться на предыдущий CTE!
)
SELECT *
FROM cte2;
Каждый следующий CTE может использовать предыдущий. Это позволяет строить пошаговые вычисления.
Пример: пошаговое вычисление
sql
WITH
-- Шаг 1: суммы по счетам
account_totals AS (
SELECT account_id, SUM(amount) AS total
FROM transactions
WHERE txn_type = 'пополнение'
GROUP BY account_id
),
-- Шаг 2: топ-счета (больше 20 000)
top_accounts AS (
SELECT account_id, total
FROM account_totals
WHERE total > 20000
)
SELECT a.client_id, t.account_id, t.total
FROM top_accounts t
JOIN accounts a ON a.id = t.account_id
ORDER BY t.total DESC;
Что CTE не делает
CTE не создаёт реальную таблицу и не сохраняет данные. Это синтаксический сахар: база данных разворачивает CTE в тот же подзапрос перед выполнением (в большинстве случаев).
Частые ошибки
- Запятая в конце последнего CTE — перед основным
SELECTзапятой нет:sqlWITH cte AS (...), -- ← лишняя запятая, ошибка! SELECT ... - Точка с запятой внутри CTE — запрос должен быть один, точка с запятой только в конце всего.
Запомни
WITH имя AS (подзапрос) → даём имя подзапросу.
Несколько CTE разделяются запятой. Последний CTE — без запятой.
Дальше идёт обычный SELECT, использующий CTE как таблицу.
Прочитайте урок до конца — прогресс засчитается автоматически