SQLLab
Теория· 8 мин· 10 XP

Проблема вложенных подзапросов

Зачем это нужно

Вложенные подзапросы — одна из самых частых причин, по которым SQL-код становится нечитаемым. Посмотри на этот запрос:

sql
SELECT client_id, total_amount
FROM (
    SELECT a.client_id, SUM(t.amount) AS total_amount
    FROM (
        SELECT id, client_id FROM accounts WHERE account_type = 'текущий'
    ) a
    JOIN transactions t ON t.account_id = a.id
    WHERE t.txn_type = 'пополнение'
    GROUP BY a.client_id
) sub
WHERE total_amount > 50000
ORDER BY total_amount DESC;

Что здесь происходит? Чтобы понять, нужно читать снизу вверх, держа в голове три уровня вложенности. Если через месяц тебе понадобится изменить фильтр — удачи.

Антипаттерны вложенных подзапросов

Проблема 1: Нечитаемость. Скобки закрываются далеко от того места, где открывались. Нельзя дать подзапросу осмысленное имя.

Проблема 2: Дублирование. Если один и тот же подзапрос нужен в нескольких местах запроса, его приходится копировать:

sql
SELECT *
FROM (SELECT account_id, SUM(amount) FROM transactions GROUP BY account_id) t1
JOIN (SELECT account_id, SUM(amount) FROM transactions GROUP BY account_id) t2
ON t1.account_id = t2.account_id;
-- Один и тот же подзапрос дважды!

Проблема 3: Сложность отладки. Нельзя запустить подзапрос отдельно, чтобы проверить промежуточный результат.

Что такое CTE

CTE (Common Table Expression) — именованный временный результат, который определяется перед основным запросом и используется в нём как обычная таблица.

sql
WITH имя_cte AS (
    -- подзапрос
    SELECT ...
)
SELECT * FROM имя_cte;

CTE — это не новая таблица в базе данных. Это способ дать имя подзапросу и вынести его «наверх» для читаемости.

Запомни

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

Прочитайте урок до конца — прогресс засчитается автоматически