Jaka jest różnica między Z CTE i Z CTE (<nazwy_kolumn>)?

11

Jak pokazano w sekcji Używanie typowych wyrażeń tabelowych w MSDN, możesz zdefiniować CTE jako:

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

i używaj go w następujący sposób:

SELECT <column_list> FROM expression_name;

Powiedzmy, że mam 2 następujące CTE

with cte1 as(
select name from Table1
)

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

Zapytanie wyprowadza takie same wyniki dla obu CTE, jak zapytanie wewnętrzne jest takie samo. Jedyną różnicą między tymi dwoma jest to, że cte2 ma nazwę kolumny ( (name)) zdefiniowaną w deklaracji.

Kiedy wykonuję oba CTE, nie widzę żadnej różnicy w planie wykonania.

Jestem tylko ciekawy, aby wiedzieć:

  • Co to za różnica, jeśli nie podam żadnych nazw kolumn w definicji CTE?
  • Dlaczego powinienem / nie powinienem określać nazw kolumn podczas tworzenia CTE?
  • Czy przypadkiem wpływa to na plan wykonania zapytania? (O ile widziałem, to nie ma znaczenia.)
Ketan
źródło

Odpowiedzi:

25

Już prawie masz odpowiedź na jedno z twoich pytań.

Na stronie MSDN po cytacie znajduje się wiersz wyjaśniający to:

Podstawowa struktura składniowa dla CTE to:

Z nazwą_wyrażenia [(nazwa_kolumny [, ... n])]

TAK JAK

(CTE_query_definition)

Lista nazw kolumn jest opcjonalna tylko wtedy, gdy w definicji zapytania podano odrębne nazwy dla wszystkich kolumn wynikowych.

(Podkreślenie dodane)

Oznaczałoby to, że musisz podać nazwy kolumn w kilku sytuacjach:

  • To by działało:

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

    WITH [test_table]  
    AS
    (
        SELECT 
            1 as [NoName]
          , CAST('1' AS CHAR(1)) as [CAST]
          , dbo.CastToChar(1) as [Function]
    )
    SELECT * FROM [test_table];
  • Nie byłoby tak, ponieważ nie ma odrębnych nazw dla kolumn:

    WITH [test_table] 
    AS
    (
        SELECT 
            1
          , CAST('1' AS CHAR(1))
          , dbo.CastToChar(1)
    )
    SELECT * FROM [test_table];
Shaneis
źródło
1
w zasadzie wersja bez kolumn jest taka sama jak wersja z kolumną, z wyjątkiem tego, że SQL musi „wywnioskować” nazwy kolumn z zapytania.
KutuluMike,
10

Anegdotycznie wolę nazywać kolumny wewnątrz CTE zamiast wewnątrz klauzuli WITH CTE (xxx) AS1 , ponieważ nigdy nie przypadkowo nie dopasujesz nazw do zawartości kolumny.

Weźmy na przykład następujący przykład:

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

Co to wyświetla? Pokazuje zawartość ykolumny pod nagłówkiem xi zawartość xkolumny pod nagłówkiem y.

Dzięki tej realizacji nigdy nie określam nazw kolumn w (xxx) ASklauzuli, zamiast tego robię to w następujący sposób:

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

To usuwa wszelkie wątpliwości dotyczące definicji kolumn.

Na całkowicie niepowiązanym marginesie; zawsze określaj nazwę schematu, odwołując się do nazw obiektów , i zakończ instrukcje średnikiem .

Max Vernon
źródło
7

Ostatecznie każda kolumna potrzebuje prawidłowej nazwy i można ją przypisać na dwa sposoby:

  1. Lista kolumn

    ;WITH cte (foo)
    AS
    ( select col from tab )
    select foo from cte;
  2. Używanie oryginalnych nazw lub aliasów kolumn

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

Kiedy robisz zarówno alias jak i listę kolumn

  1. Zarówno lista kolumn, jak i aliasy

    ;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;

Jest to podobne do definicji Widoku lub Tabeli pochodnej, w której można również określić listę nazw kolumn.

lista kolumn : Gdy masz wiele skomplikowanych obliczeń, łatwiej jest rozpoznać nazwę, ponieważ nie są one rozproszone w kodzie źródłowym. I jest łatwiej, jeśli masz rekurencyjne cte i możesz przypisać dwie różne nazwy dla tej samej kolumny w punkcie 3.

oryginalna nazwa / aliasy : Musisz przypisać alias tylko, jeśli wykonujesz obliczenia lub chcesz / musisz zmienić nazwę kolumny

dnoeth
źródło
1
„łatwiejszy do zauważenia” jest może nieco subiektywny. Wolę mieć aliasy kolumn na początku wiersza, jak w SomeAlias = SomeFunction(SomeColumn), z tylko jedną definicją kolumny na wiersz. Umożliwia to proste skanowanie po lewej stronie listy kolumn w celu znalezienia tego, którego szukasz.
Max Vernon
1
@ MaxVernon: Zgadza się, a dodanie pustych linii między obliczeniami obejmującymi wiele linii również pomaga. W zasadzie
pomijam
2
Zabawne, że wspominałeś o widokach. Nigdy nie używałem listy kolumn po nazwie widoku podczas definiowania widoku, jak w CREATE VIEW SomeView (ColA, ColB, …) AS …. Teraz, gdy już o tym wspomniałeś, myślę o takich scenariuszachCREATE VIEW MyView (G) AS WITH cte (C) AS (SELECT A AS B FROM MyTable) SELECT E AS F FROM (SELECT C AS D FROM cte) AS s (E); - jaka to by była radość z debugowania!
Andriy M