WITH CTE와 WITH CTE (<열 _ 이름>)의 차이점은 무엇입니까?


11

MSDN에서 공통 테이블 표현식 사용에 표시된대로 CTE를 다음과 같이 정의 할 수 있습니다.

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

다음과 같이 사용하십시오.

SELECT <column_list> FROM expression_name;

CTE 2 명을 팔로우한다고 가정 해 보겠습니다.

with cte1 as(
select name from Table1
)

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

내부 쿼리가 동일하므로 쿼리는 두 CTE에 대해 동일한 결과를 출력합니다. 이 두 가지의 유일한 차이점은 cte2에(name) 선언에 정의 된 열 이름 ( ) 이 있다는 입니다.

두 CTE를 모두 실행할 때 실행 계획에 차이가 없습니다.

나는 단지 궁금하다 :

  • CTE 정의에 열 이름을 지정하지 않으면 어떤 차이가 있습니까?
  • CTE를 생성 할 때 열 이름을 지정해야하는 이유는 무엇입니까?
  • 우연히 쿼리 실행 계획에 영향을 줍니까? (내가 아는 한 아무런 차이가 없습니다.)

답변:


25

당신은 이미 당신의 질문 중 하나에 대한 답을 가지고 있습니다.

에서 MSDN의 페이지,이 설명 견적 후 직접 라인이있다 :

CTE의 기본 구문 구조는 다음과 같습니다.

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

같이

(CTE_query_definition)

열 결과 목록은 모든 결과 열의 고유 이름이 쿼리 정의에 제공되는 경우에만 선택 사항입니다.

(공포 추가)

이는 몇 가지 상황에서 열 이름을 지정해야 함을 의미합니다.

  • 이것은 작동합니다 :

    WITH [test_table] ([NoName], [CAST], [Function]) 
    AS
    (
        SELECT 
            1
          , CAST('1' AS CHAR(1))
          , dbo.CastToChar(1)
    )
    SELECT * FROM [test_table];
  • 이처럼

    WITH [test_table]  
    AS
    (
        SELECT 
            1 as [NoName]
          , CAST('1' AS CHAR(1)) as [CAST]
          , dbo.CastToChar(1) as [Function]
    )
    SELECT * FROM [test_table];
  • 그러나 이것은 열의 고유 이름이 없기 때문에 그렇지 않습니다.

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

1
기본적으로 열이없는 버전은 SQL이 쿼리에서 열 이름을 "유추"해야한다는 점을 제외하고 열이있는 버전과 동일합니다.
KutuluMike

10

우연히도 이름과 열 내용이 실수로 일치하지 않기 때문에 WITH CTE (xxx) AS1 절 대신 CTE 내부의 열 이름을 지정하는 것을 선호합니다 .

예를 들어 다음 예제를 보자.

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

이것은 무엇을 표시합니까? 이것은 내용 표시 y의 절의 열 x및 내용 x절의 컬럼y .

이 실현으로, 나는 결코 에 열 이름을 지정 (xxx) AS하는 대신이 같은 그것을, 절 :

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

이것은 열 정의가 무엇인지에 대한 모든 의심을 제거합니다.

완전히 무관 한 부가 정보; 항상 개체 이름을 참조 할 때 스키마 이름을 지정 하고, 세미콜론과의 문을 종료 .


7

궁극적으로 각 열에는 유효한 이름이 필요하며 다음 두 가지 방법으로 할당 할 수 있습니다.

  1. 열 목록

    ;WITH cte (foo)
    AS
    ( select col from tab )
    select foo from cte;
  2. 원래 열 이름 또는 별명 사용

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

별칭열 목록을 모두 수행하는 경우

  1. 열 목록 및 별칭

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

이것은 열 이름 목록을 지정할 수있는 뷰 또는 파생 테이블의 정의와 유사합니다.

column list : 복잡한 계산이 많으면 소스 코드를 통해 흩어지지 않기 때문에 이름을 쉽게 찾을 수 있습니다. 그리고 재귀 cte를 얻는 것이 더 쉬우 며 # 3의 동일한 열에 대해 서로 다른 두 개의 이름을 지정할 수 있습니다.

원래 이름 / 별칭 : 계산을 수행하거나 열의 이름을 바꾸고 싶은 경우에만 별칭 을 지정하면됩니다.


1
"쉽게 찾기"는 아마도 약간 주관적 일 것입니다. 에서와 같이 줄의 시작 부분에 열 별명을 갖는 것을 선호합니다 SomeAlias = SomeFunction(SomeColumn). 그러면 열 목록의 왼쪽을 간단하게 스캔하여 원하는 것을 찾을 수 있습니다.
Max Vernon

1
@MaxVernon : 맞습니다. 여러 줄에 걸친 계산 사이에 빈 줄을 추가하면 도움이됩니다. 사실 나는 열리스트도 대부분 생략한다.
dnoeth

2
당신이 전망을 언급 한 것이 재밌습니다. 에서처럼 뷰를 정의 할 때 뷰 이름 뒤에 열 목록을 사용한 적이 없습니다 CREATE VIEW SomeView (ColA, ColB, …) AS …. 이제 당신이 그것을 가져 왔으므로, 나는 같은 시나리오를 생각하고 CREATE 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);있습니다.
Andriy M
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.