В этом руководстве вы узнаете об общем табличном выражении(CTE) в SQL Server с использованием предложения WITH.
Введение в CTE в SQL Server
CTE означает общее табличное выражение. CTE позволяет определить временный именованный набор результатов, который временно доступен в области выполнения оператора, например SELECT, INSERT, UPDATE, DELETE или MERGE.
Ниже показан общий синтаксис CTE в SQL Server:
WITH expression_name[(column_name [,...])] AS (CTE_definition) SQL_statement;
В этом синтаксисе:
- Сначала укажите имя выражения(expression_name), на которое вы сможете ссылаться позже в запросе.
- Далее укажите список столбцов, разделенных запятыми, после expression_name. Количество столбцов должно быть таким же, как количество столбцов, определенное в CTE_definition.
- Затем используйте ключевое слово AS после имени выражения или списка столбцов, если указан список столбцов.
- После этого определите оператор SELECT, набор результатов которого заполняет общее табличное выражение.
- Наконец, обратитесь к общему табличному выражению в запросе(SQL_statement), например, SELECT, INSERT, UPDATE, DELETE или MERGE.
Мы предпочитаем использовать общие табличные выражения вместо использования подзапросов, поскольку общие табличные выражения более читабельны. Мы также используем CTE в запросах, которые содержат аналитические функции(или оконные функции )
Примеры CTE-выражений SQL Server
Давайте рассмотрим несколько примеров использования распространенных табличных выражений.
A) Простой пример SQL Server CTE
В этом запросе используется CTE для возврата объемов продаж по торговому персоналу в 2018 году:
WITH cte_sales_amounts(staff, sales, year) AS(
SELECT
first_name + ' ' + last_name,
SUM(quantity * list_price *(1 - discount)),
YEAR(order_date)
FROM
sales.orders o
INNER JOIN sales.order_items i ON i.order_id = o.order_id
INNER JOIN sales.staffs s ON s.staff_id = o.staff_id
GROUP BY
first_name + ' ' + last_name,
year(order_date)
)
SELECT
staff,
sales
FROM
cte_sales_amounts
WHERE
year = 2018;
На следующем рисунке показан результирующий набор:

В этом примере:
- Сначала мы определили cte_sales_amounts как имя общего табличного выражения. CTE возвращает результат, состоящий из трех столбцов: staff, year и sales, полученных из запроса определения.
- Во-вторых, мы построили запрос, который возвращает общую сумму продаж по торговому персоналу и году, запрашивая данные из таблиц orders, order_items и staffs.
- В-третьих, мы ссылаемся на CTE во внешнем запросе и выбираем только те строки, год которых — 2018.
Отмечено, что этот пример предназначен исключительно для демонстрационных целей, чтобы помочь вам постепенно понять, как работают общие табличные выражения. Существует более оптимальный способ достижения результата без использования CTE.
Б) Использование общего табличного выражения для создания средних значений отчета на основе подсчетов
В этом примере CTE используется для возврата среднего количества заказов на продажу в 2018 году для всех сотрудников отдела продаж.
WITH cte_sales AS(
SELECT
staff_id,
COUNT(*) order_count
FROM
sales.orders
WHERE
YEAR(order_date) = 2018
GROUP BY
staff_id
)
SELECT
AVG(order_count) average_orders_by_staff
FROM
cte_sales;
Вот что получилось:
average_orders_by_staff ----------------------- 48 (1 row affected)
В этом примере:
Во-первых, мы использовали cte_sales как имя общего табличного выражения. Мы пропустили список столбцов CTE, поэтому он выводится из оператора определения CTE. В этом примере он включает столбцы staff_id и order_count.
Во-вторых, мы используем следующий запрос для определения набора результатов, который заполняет общее табличное выражение cte_sales. Запрос возвращает количество заказов в 2018 году по торговому персоналу.
SELECT
staff_id,
COUNT(*) order_count
FROM
sales.orders
WHERE
YEAR(order_date) = 2018
GROUP BY
staff_id;
В-третьих, мы ссылаемся на cte_sales во внешнем операторе и используем функцию AVG(), чтобы получить средний заказ продаж по всем сотрудникам.
SELECT
AVG(order_count) average_orders_by_staff
FROM
cte_sales;
C) Пример использования нескольких SQL Server CTE в одном запросе
В следующем примере используются два CTE cte_category_counts и cte_category_sales для возврата количества продуктов и продаж для каждой категории продуктов. Внешний запрос объединяет два CTE с использованием столбца category_id.
WITH cte_category_counts(
category_id,
category_name,
product_count
)
AS(
SELECT
c.category_id,
c.category_name,
COUNT(p.product_id)
FROM
production.products p
INNER JOIN production.categories c
ON c.category_id = p.category_id
GROUP BY
c.category_id,
c.category_name
),
cte_category_sales(category_id, sales) AS(
SELECT
p.category_id,
SUM(i.quantity * i.list_price *(1 - i.discount))
FROM
sales.order_items i
INNER JOIN production.products p
ON p.product_id = i.product_id
INNER JOIN sales.orders o
ON o.order_id = i.order_id
WHERE order_status = 4 -- completed
GROUP BY
p.category_id
)
SELECT
c.category_id,
c.category_name,
c.product_count,
s.sales
FROM
cte_category_counts c
INNER JOIN cte_category_sales s
ON s.category_id = c.category_id
ORDER BY
c.category_name;
Вот результат:

В этом руководстве вы узнали, как использовать общие табличные выражения(CTE) в SQL Server для построения сложных запросов в простой и понятной форме.




