Sự khác biệt giữa VỚI CTE & VỚI CTE (<cột_names>) là gì?


11

Như được hiển thị trong Sử dụng biểu thức bảng chung trên MSDN, bạn có thể định nghĩa CTE là:

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

và sử dụng nó như:

SELECT <column_list> FROM expression_name;

Giả sử tôi có 2 CTE

with cte1 as(
select name from Table1
)

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

Một truy vấn đưa ra kết quả giống nhau cho cả hai CTE vì truy vấn bên trong là như nhau. Sự khác biệt duy nhất giữa hai điều này là cte2 có tên cột ( (name)) được xác định trong khai báo của nó.

Khi tôi thực thi cả hai CTE, tôi không thấy bất kỳ sự khác biệt nào trong kế hoạch thực hiện.

Tôi chỉ tò mò muốn biết:

  • Có gì khác biệt nếu tôi không chỉ định bất kỳ tên cột nào trong định nghĩa CTE?
  • Tại sao tôi nên / không nên chỉ định tên cột trong khi tạo CTE?
  • Nó có ảnh hưởng đến kế hoạch thực hiện truy vấn bởi bất kỳ cơ hội? (Theo như tôi đã thấy, nó không tạo ra sự khác biệt nào.)

Câu trả lời:


25

Bạn gần như đã có câu trả lời cho một trong những câu hỏi của bạn rồi.

Trong trang MSDN , có một dòng ngay sau trích dẫn của bạn giải thích điều này:

Cấu trúc cú pháp cơ bản cho CTE là:

VỚI biểu thức_name [(cột_name [, ... n])]

NHƯ

(CTE_query_def định)

Danh sách tên cột chỉ là tùy chọn nếu tên riêng biệt cho tất cả các cột kết quả được cung cấp trong định nghĩa truy vấn.

(Nhấn mạnh thêm)

Điều này có nghĩa là bạn sẽ cần chỉ định tên cột trong một vài tình huống:

  • Điều này sẽ làm việc:

    WITH [test_table] ([NoName], [CAST], [Function]) 
    AS
    (
        SELECT 
            1
          , CAST('1' AS CHAR(1))
          , dbo.CastToChar(1)
    )
    SELECT * FROM [test_table];
    
  • như thế này:

    WITH [test_table]  
    AS
    (
        SELECT 
            1 as [NoName]
          , CAST('1' AS CHAR(1)) as [CAST]
          , dbo.CastToChar(1) as [Function]
    )
    SELECT * FROM [test_table];
    
  • Nhưng điều này sẽ không vì nó không có tên riêng biệt cho các cột:

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

1
về cơ bản, phiên bản không có cột giống như phiên bản có cột ngoại trừ SQL phải "suy ra" tên cột từ truy vấn.
KutuluMike

10

Thông thường, tôi thích đặt tên cho các cột bên trong CTE thay vì bên trong mệnh đề WITH CTE (xxx) AS1 vì bạn sẽ không bao giờ vô tình khớp tên giữa các nội dung với cột.

Ví dụ như ví dụ sau:

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

Màn hình này hiển thị cái gì? Nó hiển thị nội dung của ycột dưới tiêu đề xvà nội dung của xcột dưới tiêu đề y.

Với nhận thức này, tôi không bao giờ chỉ định tên cột trong (xxx) ASmệnh đề, thay vào đó tôi làm như thế này:

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

Điều này loại bỏ tất cả nghi ngờ về các định nghĩa cột là gì.

Trên một lưu ý phụ hoàn toàn không liên quan; luôn chỉ định tên lược đồ khi tham chiếu tên đối tượngkết thúc câu lệnh của bạn bằng dấu chấm phẩy .


7

Cuối cùng, mỗi cột cần một tên hợp lệ và bạn có thể gán nó theo hai cách:

  1. Danh sách cột

    ;WITH cte (foo)
    AS
    ( select col from tab )
    select foo from cte;
    
  2. Sử dụng tên cột hoặc bí danh

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

Khi bạn làm cả danh sách bí danhcột

  1. Cả danh sách cột & bí danh

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

Điều này tương tự với định nghĩa của Chế độ xem hoặc Bảng có nguồn gốc, nơi bạn cũng có thể chỉ định danh sách các tên cột.

danh sách cột : Khi bạn có nhiều phép tính phức tạp, việc phát hiện tên sẽ dễ dàng hơn vì chúng không bị phân tán qua mã nguồn. Và sẽ dễ dàng hơn nếu bạn có một cte đệ quy và bạn có thể gán hai tên khác nhau cho cùng một cột trong # 3.

tên / bí danh gốc : Bạn chỉ phải gán bí danh nếu bạn thực hiện phép tính hoặc muốn / phải đổi tên cột


1
"Dễ phát hiện hơn" có lẽ hơi chủ quan. Tôi thích có các bí danh cột ở đầu dòng, như trong SomeAlias = SomeFunction(SomeColumn), chỉ với một định nghĩa cột trên mỗi dòng. Điều này cho phép quét đơn giản xuống phía bên trái của danh sách cột để xác định vị trí bạn đang tìm kiếm.
Max Vernon

1
@MaxVernon: Điều đó đúng và thêm các dòng trống giữa các phép tính kéo dài nhiều dòng cũng có ích. Trên thực tế, tôi hầu như bỏ qua danh sách cột, quá ...
dnoeth

2
Hài hước mà bạn đề cập đến quan điểm. Tôi chưa bao giờ sử dụng danh sách cột sau tên xem khi xác định chế độ xem, như trong CREATE VIEW SomeView (ColA, ColB, …) AS …. Bây giờ bạn đã đưa ra điều đó, tôi đang nghĩ về các kịch bản như 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);- thật là một niềm vui để gỡ lỗi!
Andriy M
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.