Сохраняя это простым и как сделать несколько CTE в запросе

156

У меня есть этот простой запрос T-SQL, он генерирует несколько столбцов из таблицы, а также объединяет информацию из других связанных таблиц.

Моя модель данных проста. У меня запланированное мероприятие с участниками. Мне нужно знать, сколько участников участвуют в каждом мероприятии.

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

Это позволит мне присоединиться к этой информации для каждого запланированного события. Сохранение запроса простым

Однако мне нравится, чтобы мои запросы были простыми. Если в будущем мне понадобятся дополнительные временные результаты, доступные во время простого запроса, что мне делать?

Мне бы очень понравилось, если бы у меня было несколько CTE, но я не могу, верно? Какие у меня есть варианты?

Я исключил представления и действия на уровне данных приложения. Я предпочитаю изолировать свои SQL-запросы.

Джон Лейдгрен
источник

Ответы:

297

Вы можете иметь несколько CTEs в одном запросе, а также повторно использовать CTE:

WITH    cte1 AS
        (
        SELECT  1 AS id
        ),
        cte2 AS
        (
        SELECT  2 AS id
        )
SELECT  *
FROM    cte1
UNION ALL
SELECT  *
FROM    cte2
UNION ALL
SELECT  *
FROM    cte1

Однако обратите внимание, что это SQL Serverможет переоценивать CTEкаждый раз, когда к нему обращаются, поэтому, если вы используете такие значения, как RAND(), NEWID()и т. Д., Они могут меняться между CTEвызовами.

Quassnoi
источник
3
Это было так просто. документация MSDN была немного нечеткой по этому вопросу, я не смог найти ничего убедительного. Большое спасибо!
Джон Лейдгрен
1
Это задокументировано в WITH common_table_expression (Transact-SQL) . Вы можете видеть это в разделе синтаксиса (обратите особое внимание на [ ,...n ]in [ WITH <common_table_expression> [ ,...n ] ]. Пример C, «Использование нескольких определений CTE в одном запросе»), это явно выражено. К сожалению, этот пример не представлен в документации по SQL 2008 и старше (т. е. пример не был представлен, когда ОП опубликовал вопрос).
Брайан,
Я получаю вдвое больше записей об этом: /
Том Стиккель
@TomStickel попробуйте использовать только половину запроса, перед последнимUNION ALL
Quassnoi
@Quassnoi Да, это сработало. Я сделал это после написания комментария. Не уверен, почему этот второй союз даже там ...
Том Стиккель
90

Вы, безусловно, можете иметь несколько CTE в одном выражении запроса. Вам просто нужно отделить их запятой. Вот пример. В приведенном ниже примере есть два CTE. Один назван, CategoryAndNumberOfProductsа второй назван ProductsOverTenDollars.

WITH CategoryAndNumberOfProducts (CategoryID, CategoryName, NumberOfProducts) AS
(
   SELECT
      CategoryID,
      CategoryName,
      (SELECT COUNT(1) FROM Products p
       WHERE p.CategoryID = c.CategoryID) as NumberOfProducts
   FROM Categories c
),

ProductsOverTenDollars (ProductID, CategoryID, ProductName, UnitPrice) AS
(
   SELECT
      ProductID,
      CategoryID,
      ProductName,
      UnitPrice
   FROM Products p
   WHERE UnitPrice > 10.0
)

SELECT c.CategoryName, c.NumberOfProducts,
      p.ProductName, p.UnitPrice
FROM ProductsOverTenDollars p
   INNER JOIN CategoryAndNumberOfProducts c ON
      p.CategoryID = c.CategoryID
ORDER BY ProductName
Рэнди Миндер
источник
5
@JohnLeidegren: публикация правильного ответа в течение 2 минут после первого правильного ответа заслуживает отката, который я дал, по крайней мере.
Питер Маджид