Rester simple et comment faire plusieurs CTE dans une requête

156

J'ai cette simple requête T-SQL, elle émet un tas de colonnes à partir d'une table et joint également les informations d'autres tables liées .

Mon modèle de données est simple. J'ai un événement programmé, avec des participants. J'ai besoin de savoir combien de participants participent à chaque événement.

Ma solution à cela est d'ajouter un CTE qui regroupe les événements programmés et compte le nombre de participants.

Cela me permettra de participer à ces informations par événement programmé. Garder la requête simple.

Cependant, j'aime garder mes requêtes simples, si jamais j'ai besoin à l'avenir d'avoir des résultats temporaires supplémentaires accessibles pendant ma requête simple, que dois-je faire?

Je l'aimerais vraiment, si je pouvais avoir plusieurs CTE mais je ne peux pas, non? Quelles sont mes options ici?

J'ai exclu les vues et les actions au niveau de la couche de données d'application. Je préfère isoler mes requêtes SQL.

John Leidegren
la source

Réponses:

297

Vous pouvez avoir plusieurs CTEs dans une requête, ainsi que réutiliser un 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

Notez, cependant, que SQL Serverpeut réévaluer le à CTEchaque fois qu'il est accédé, donc si vous utilisez des valeurs telles que RAND(), NEWID()etc., elles peuvent changer entre les CTEappels.

Quassnoi
la source
3
C'était aussi simple que ça. la documentation MSDN était un peu floue autour du problème, je n'ai rien trouvé de concluant. Merci beaucoup!
John Leidegren
1
Il est documenté dans WITH common_table_expression (Transact-SQL) . Vous pouvez le voir dans la section sur la syntaxe (notez particulièrement l' [ ,...n ]in [ WITH <common_table_expression> [ ,...n ] ]. Exemple C, «Utilisation de plusieurs définitions CTE dans une seule requête», l'appelle explicitement. Malheureusement, cet exemple n'est pas fourni dans la documentation de SQL 2008 et plus ancien (c'est-à-dire que l'exemple n'a pas été fourni lorsque le PO a posté la question).
Brian
J'obtiens le double du nombre de disques sur ceci: /
Tom Stickel
@TomStickel essayez d'utiliser uniquement la moitié de la requête, avant la dernièreUNION ALL
Quassnoi
@Quassnoi Oui, cela a fonctionné. Je l'ai fait après avoir écrit le commentaire. Je ne sais pas pourquoi cette 2ème union est même là ...
Tom Stickel
90

Vous pouvez certainement avoir plusieurs CTE dans une seule expression de requête. Il vous suffit de les séparer par une virgule. Voici un exemple. Dans l'exemple ci-dessous, il y a deux CTE. L'un est nommé CategoryAndNumberOfProductset le second est nommé 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
la source
5
@JohnLeidegren: publier une réponse correcte dans les 2 minutes suivant la première bonne réponse mérite un vote favorable, que j'ai au moins donné.
Peter Majeed