Можно ли использовать алиас таблицы вне CTE?
Что проверяют
Понимаете ли вы область видимости имён в SQL: что видно внутри CTE, что снаружи и на каком шаге выполнения запроса имя вообще появляется. Следом часто просят объяснить, почему алиас колонки из SELECT нельзя использовать в WHERE того же запроса.
Как отвечать
Если речь об алиасе, объявленном внутри CTE, то нет. Алиас из FROM orders o живёт только в запросе этого CTE. Снаружи CTE виден как отдельная таблица под своим именем, и обращаются к нему через это имя или через новый алиас:
WITH paid AS (SELECT o.user_id, o.amount FROM orders o WHERE o.status = 'paid') SELECT p.user_id, SUM(p.amount) FROM paid p GROUP BY p.user_id;
Здесь o снаружи недоступен, а p это уже другой алиас, выданный CTE в основном запросе. Наружу выходят только колонки CTE, поэтому нужное поле надо явно вывести в его SELECT, а имена колонок можно задать списком: WITH paid(user_id, amount) AS (...). Сами алиасы таблиц, конечно, работают в любом запросе, CTE для них не нужен.
Что ещё стоит проговорить:
- сам CTE виден только в той инструкции, к которой приписан
WITH. В следующем запросе его уже нет, для повторного использования нужна временная таблица или представление; - соседние CTE видят предыдущие по имени: второй в списке
WITHможет читать из первого; - коррелированный подзапрос видит алиасы внешнего запроса, обратное неверно;
- алиасы колонок подчиняются логическому порядку выполнения:
FROM,WHERE,GROUP BY,HAVING,SELECT,ORDER BY. Поэтому вWHEREалиаса изSELECTещё нет, а вORDER BYуже есть. PostgreSQL и MySQL разрешают его и вGROUP BYкак расширение стандарта, а ClickHouse позволяет ссылаться на алиас почти в любом месте запроса.
Где спотыкаются
Обращаются к полю, которое не вывели в SELECT CTE. Внутренняя таблица orders снаружи не видна, видно только то, что CTE вернул.
Путают диалекты. Запрос с алиасом в GROUP BY работает в PostgreSQL, а в SQL Server падает.
Дав таблице алиас, продолжают писать полное имя: FROM orders o WHERE orders.status = .... PostgreSQL ответит ошибкой о неверной ссылке на элемент FROM: после алиаса исходное имя в этом запросе закрыто.