Mantendo a simplicidade e como executar várias CTE em uma consulta

156

Eu tenho essa consulta T-SQL simples, que emite várias colunas de uma tabela e também junta informações de outras tabelas relacionadas .

Meu modelo de dados é simples. Eu tenho um evento agendado, com participantes. Preciso saber quantos participantes participam de cada evento.

Minha solução para isso é adicionar um CTE que agrupe eventos agendados e conte o número de participantes.

Isso permitirá que eu junte essas informações por evento agendado. Mantendo a consulta simples.

No entanto, gosto de manter minhas consultas simples. Se, no futuro, precisar de resultados temporários adicionais acessíveis durante minha consulta simples, o que devo fazer?

Eu realmente gostaria, se eu pudesse ter vários CTEs, mas não posso, certo? Quais são minhas opções aqui?

Eu excluí visualizações e fazia as coisas na camada de dados do aplicativo. Eu prefiro isolar minhas consultas SQL.

John Leidegren
fonte

Respostas:

297

Você pode ter vários CTEs em uma consulta e reutilizar a 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

Note, no entanto, que SQL Serverpode reavaliar a CTEcada vez que é acessado, por isso, se você estiver usando valores como RAND(), NEWID()etc., eles podem mudar entre as CTEchamadas.

Quassnoi
fonte
3
Era simples assim. a documentação do MSDN estava um pouco confusa com o problema, não encontrei nada conclusivo. Muito obrigado!
John Leidegren
1
Está documentado em WITH common_table_expression (Transact-SQL) . Você pode ver isso estão na seção sintaxe (tomar nota especial do [ ,...n ]no [ WITH <common_table_expression> [ ,...n ] ]. Exemplo C, "Usando várias definições CTE em uma única consulta", chama isso de forma explícita. Infelizmente, este exemplo não é fornecido na documentação do SQL 2008 e mais velho (ou seja, o exemplo não foi fornecido quando o OP postou a pergunta).
Brian
Eu recebo o dobro da quantidade de registros sobre isso: /
Tom Stickel
@TomStickel tentar usar apenas a metade da consulta, antes do últimoUNION ALL
Quassnoi
@ Quassnoi Sim, isso funcionou. Fiz isso depois de escrever o comentário. Não sei por que segunda união é ainda lá ...
Tom Stickel
90

Você certamente pode ter vários CTEs em uma única expressão de consulta. Você só precisa separá-los com uma vírgula. Aqui está um exemplo. No exemplo abaixo, existem dois CTEs. Um é nomeado CategoryAndNumberOfProductse o segundo é nomeado 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
Randy Minder
fonte
5
@JohnLeidegren: postar uma resposta correta dentro de 2 minutos da primeira resposta correta merece um voto positivo, que eu dei, pelo menos.
precisa