Перейти к основному содержимому
Модуль 7 · Урок 1 из 425/57 в курсе~12 min
Уроки модуля (1/4)

CTE: многошаговые запросы с помощью With

Реальные запросы имеют тенденцию к увеличению: три JOIN, GROUP BY, подзапрос, еще один подзапрос… и они становятся нечитаемыми. CTE («Общая таблица Выражения", предложение WITH) позволяет вам присвоить имя промежуточный шаг и используйте его, как если бы это была таблица в основном запросе.

Основной синтаксис

SQL
WITH nome_cte AS (
  SELECT …    -- query interna
)
SELECT …      -- query principale, usa nome_cte come fosse una tabella
FROM   nome_cte;

CTE действителен только для следующего за ним запроса: он не сохраняется. исполнение.

Пример

Найдите трех клиентов, которые потратили больше всего (сумма сверх доставленных заказов):

SQL
WITH total_spent AS (
  SELECT o.customer_id,
         SUM(oi.quantity * oi.unit_price) AS total
  FROM   orders      o
  JOIN   order_items oi ON oi.order_id = o.id
  WHERE  o.status = 'delivered'
  GROUP BY o.customer_id
)
SELECT c.email,
       s.total
FROM   total_spent s
JOIN   customers c ON c.id = s.customer_id
ORDER BY s.total DESC
LIMIT  3;

Прочтите по-английски: "сначала рассчитайте расходы на одного клиента, а затем присоединитесь к клиентов и занять верхние 3". Без CTE вам понадобится встроенный подзапрос в FROM (правильный, но более шумный).

Несколько CTE в каскаде

Вы можете определить несколько CTE, разделенных запятыми, и каждый из них может ссылаться на к предыдущим:

SQL
WITH total_spent AS (
  SELECT customer_id, SUM(quantity * unit_price) AS total
  FROM   order_items oi
  JOIN   orders      o ON oi.order_id = o.id
  WHERE  o.status = 'delivered'
  GROUP BY customer_id
),
average AS (
  SELECT AVG(total) AS total_average
  FROM   total_spent
)
SELECT c.email, s.total
FROM   total_spent s
JOIN   customers c ON c.id = s.customer_id
CROSS JOIN average
WHERE  s.total > average.total_average
ORDER BY s.total DESC;

CROSS JOIN average, потому что average всегда имеет одну строку: Декартово произведение просто добавляет total_average к каждой строке результата.

CTE против подзапроса: когда какой использовать

CTE сияют, когда:

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

Встроенный подзапрос является более кратким для шага, используемого только один раз.

Попробуйте это

Упражнение#sql.m7.l1.e1
Попыток: 0Загрузка…

Используйте CTE с именем «total_spent», который вычисляет для каждого клиента общие затраты (SUM(quantity * unit_price)) по доставленным заказам. Затем в основном запросе покажите адрес электронной почты и общую сумму для трех крупнейших тратителей. Упорядочить по убыванию суммы, ограничение до 3.

Загрузка редактора…
Показать подсказку

Внутри суммы CTE количество * unit_price. В основном запросе ПРИСОЕДИНЯЙТЕСЬ к клиентам по идентификатору.

Решение доступно после 3 попыток

Обзор упражнения

Упражнение#sql.m7.l1.e2
Попыток: 0Загрузка…

Тот же CTE «total_spent», что и в предыдущем упражнении. В основном запросе покажите адрес электронной почты и общую сумму для клиентов, чьи расходы превышают средние расходы (по всем клиентам, у которых есть хотя бы один доставленный заказ). Упорядочить по убыванию суммы.

Загрузка редактора…
Показать подсказку

Скалярный подзапрос в WHERE: SELECT AVG(total) FROM total_spent.

Решение доступно после 3 попыток