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

Ответ

Общие табличные выражения (CTE, Common Table Expressions) — это именованные временные результирующие наборы, которые определяются в рамках выполнения одного SQL-запроса (инструкции SELECT, INSERT, UPDATE, DELETE или MERGE). CTE существуют только на время выполнения этого запроса.

Ключевые особенности и синтаксис:

  • Определяются с помощью ключевого слова WITH.
  • Улучшают читаемость и поддерживаемость, позволяя разбивать сложные запросы на логические блоки.
  • Могут ссылаться на себя, что позволяет создавать рекурсивные запросы (например, для обхода иерархий).

Базовый пример (нерекурсивный CTE):

WITH HighValueOrders AS (
    -- Определение CTE
    SELECT OrderID, CustomerID, TotalAmount
    FROM Orders
    WHERE TotalAmount > 10000
)
-- Основной запрос, использующий CTE как обычную таблицу
SELECT 
    c.CustomerName,
    hvo.TotalAmount
FROM HighValueOrders hvo
JOIN Customers c ON hvo.CustomerID = c.CustomerID
ORDER BY hvo.TotalAmount DESC;

Преимущества использования CTE:

  1. Улучшенная читаемость: Заменяет вложенные подзапросы, делая логику запроса более линейной и понятной.
  2. Избегание дублирования: Если один и тот же подзапрос используется в запросе несколько раз, его можно вынести в CTE и ссылаться на него по имени.
  3. Рекурсивные запросы: Единственный стандартный SQL-способ для рекурсивной обработки данных (например, построение дерева подчинённых из таблицы сотрудников).

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

Ответ 18+ 🔞

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

Вот смотри, представь: ты пишешь SQL, и там такие вложенные подзапросы, что глаза на лоб лезут. А CTE — это как сказать базе: «Слушай, давай я сначала тут посчитаю вот эту промежуточную хрень, назову её как-нибудь понятно, а потом уже буду с ней работать». И всё это в рамках одного большого запроса, ёпта!

Как это выглядит, если по-простому: Начинаешь с волшебного слова WITH, потом называешь эту временную штуку, а в скобках пишешь, что туда должно попасть. Как будто объявляешь локальную переменную, только для данных.

WITH ЗаказыПобольше AS ( -- Вот объявил временную сущность
    SELECT OrderID, CustomerID, TotalAmount
    FROM Orders
    WHERE TotalAmount > 10000 -- Отфильтровал всё, что дороже 10к
)
-- А теперь работаю с ней, как с обычной таблицей
SELECT 
    c.CustomerName,
    zpp.TotalAmount
FROM ЗаказыПобольше zpp -- Ссылаюсь на неё по имени
JOIN Customers c ON zpp.CustomerID = c.CustomerID
ORDER BY zpp.TotalAmount DESC;

И зачем это всё, спросишь? А вот зачем, ядрёна вошь:

  1. Читаемость, ёбана! Вместо того чтобы впихивать один SELECT в другой, а тот — в третий, и в итоге получить многоэтажную пиздопроебину, ты раскладываешь логику по полочкам. Сначала один блок, потом второй, потом из них собираешь итог. Глаза не сломаешь.

  2. Чтобы не повторяться. Бывает же, одна и та же логика нужна в запросе в нескольких местах. Вместо того чтобы копипастить один и тот же подзапрос и рихтовать его в трёх местах, если что-то поменяется, ты выносишь его в CTE. Изменил в одном месте — и везде подтянулось. Удобно, блядь!

  3. Самое мощное — рекурсия. Вот это реально магия. Например, у тебя таблица сотрудников, где у каждого есть начальник. И тебе надо получить всю цепочку подчинённых от самого верхнего шефа до самого нижнего менеджера. С обычными запросами — головная боль, а с рекурсивным CTE — элегантно и просто. Оно умеет вызывать само себя, пока не пройдёт всю иерархию. Красота!

Короче, CTE — это не какая-то сверхсложная фича, а просто нормальный, человеческий способ сделать свой код чище и понятнее. Особенно когда запрос превращается в монстра, который и сам через неделю не разберёт.