web-dev-qa-db-fra.com

Quelle est la différence entre WITH CTE ET WITH CTE (<column_names>)?

Comme indiqué dans tilisation des expressions de table communes sur MSDN, vous pouvez définir un CTE comme:

WITH expression_name [ ( column_name [,...n] ) ]
AS
( CTE_query_definition )

et l'utiliser comme:

SELECT <column_list> FROM expression_name;

Disons que j'ai suivi 2 CTE

with cte1 as(
select name from Table1
)

with cte2(name) as(
select name from Table1
)

Une requête génère les mêmes résultats pour les deux CTE car la requête interne est identique. La seule différence entre ces deux est que cte2 a un nom de colonne ((name)) défini dans sa déclaration.

Lorsque j'exécute les deux CTE, je ne vois aucune différence dans le plan d'exécution.

Je suis juste curieux de savoir:

  • Quelle différence cela fait-il si je ne spécifie aucun nom de colonne dans la définition CTE?
  • Pourquoi devrais-je/ne dois-je pas spécifier de noms de colonnes lors de la création de CTE?
  • Cela affecte-t-il le plan d'exécution des requêtes par hasard? (Pour autant que je l'ai vu, cela ne fait aucune différence.)
11
Ketan

Vous avez déjà presque la réponse à l'une de vos questions.

Dans la page MSDN , il y a une ligne directement après votre citation qui explique ceci:

La structure de syntaxe de base pour un CTE est:

AVEC nom_expression [(nom_colonne [ ... n])]

COMME

(CTE_query_definition)

La liste des noms de colonne n'est facultative que si des noms distincts pour toutes les colonnes résultantes sont fournis dans la définition de la requête.

(Italiques ajoutés)

Cela signifierait que vous auriez besoin de spécifier des noms de colonne dans quelques situations:

  • Cela fonctionnerait:

    WITH [test_table] ([NoName], [CAST], [Function]) 
    AS
    (
        SELECT 
            1
          , CAST('1' AS CHAR(1))
          , dbo.CastToChar(1)
    )
    SELECT * FROM [test_table];
    
  • comme cela:

    WITH [test_table]  
    AS
    (
        SELECT 
            1 as [NoName]
          , CAST('1' AS CHAR(1)) as [CAST]
          , dbo.CastToChar(1) as [Function]
    )
    SELECT * FROM [test_table];
    
  • Mais ce ne serait pas le cas car il n'a pas de noms distincts pour les colonnes:

    WITH [test_table] 
    AS
    (
        SELECT 
            1
          , CAST('1' AS CHAR(1))
          , dbo.CastToChar(1)
    )
    SELECT * FROM [test_table];
    
25
Shaneis

Pour l'anecdote, je préfère nommer les colonnes à l'intérieur du CTE plutôt qu'à l'intérieur de la WITH CTE (xxx) AS1 puisque vous ne mapperez jamais par inadvertance les noms par rapport au contenu des colonnes.

Prenons par exemple l'exemple suivant:

;WITH MyCTE (x, y)
AS 
(
    SELECT mt.y
         , mt.x
    FROM MySchema.MyTable mt
)
SELECT MyCTE.x
     , MyCTE.y
FROM MyCTE;

Qu'est-ce que cela affiche? Il affiche le contenu de la colonne y sous l'en-tête de x et le contenu de la colonne x sous l'en-tête y.

Avec cette réalisation, je ne spécifie jamais les noms de colonnes dans le (xxx) AS clause, à la place je le fais comme ceci:

;WITH MyCTE
AS 
(
    SELECT Alias1 = mt.y
         , Alias2 = mt.x
    FROM MySchema.MyTable mt
)
SELECT MyCTE.Alias1
     , MyCTE.Alias2
FROM MyCTE;

Cela supprime tout doute sur les définitions de colonne.

Sur une note latérale totalement indépendante; spécifiez toujours le nom du schéma lors du référencement des noms d'objet , et terminez vos instructions par un point-virgule .

10
Max Vernon

Au final, chaque colonne a besoin d'un nom valide et vous pouvez l'attribuer de deux manières:

  1. Liste des colonnes

    ;WITH cte (foo)
    AS
    ( select col from tab )
    select foo from cte;
    
  2. Utilisation de noms de colonnes ou d'alias originaux

    ;WITH cte
    AS
    ( select col from tab )
    select col from cte;
    

Lorsque vous faites à la fois alias et liste de colonnes

  1. Liste des colonnes et alias

    ;WITH cte (foo, bar)
    AS
    ( select col1         -- not valid in outer Select
             col2 as colx -- not valid in outer Select
      from tab )
    select foo, bar from cte;
    

Ceci est similaire à la définition d'une vue ou d'une table dérivée, où vous pouvez également spécifier une liste de noms de colonnes.

liste des colonnes: Lorsque vous avez beaucoup de calculs complexes, il est plus facile de repérer le nom, car ils ne sont pas dispersés dans le code source. Et c'est plus facile si vous avez un cte récursif et vous pouvez assigner deux noms différents pour la même colonne dans # 3.

nom/alias d'origine: Vous ne devez attribuer un alias que si vous effectuez un calcul ou si vous voulez/devez renommer une colonne

7
dnoeth