ข้อแตกต่างระหว่าง WITH CTE และ WITH CTE (<column_name>) คืออะไร


11

ดังที่แสดงในการใช้ Common Table Expressionsบน MSDN คุณสามารถกำหนด CTE เป็น:

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

และใช้มันเช่น:

SELECT <column_list> FROM expression_name;

สมมติว่าฉันมี 2 CTE ต่อไปนี้

with cte1 as(
select name from Table1
)

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

แบบสอบถามส่งผลลัพธ์เดียวกันสำหรับ CTE ทั้งสองเนื่องจากแบบสอบถามภายในเหมือนกัน ข้อแตกต่างระหว่างสองสิ่งนี้คือcte2มีชื่อคอลัมน์ ( (name)) ที่กำหนดไว้ในการประกาศ

เมื่อฉันดำเนินการ CTE ทั้งสองฉันไม่เห็นความแตกต่างในแผนการดำเนินการ

ฉันแค่อยากรู้ว่า:

  • หากฉันไม่ได้ระบุชื่อคอลัมน์ใด ๆ ในคำนิยาม CTE
  • เหตุใดฉันจึงควร / ไม่ควรระบุชื่อคอลัมน์ขณะสร้าง CTE
  • มันมีผลต่อแผนการดำเนินการแบบสอบถามโดยบังเอิญหรือไม่? (เท่าที่ฉันได้เห็นมันไม่ได้สร้างความแตกต่าง)

คำตอบ:


25

คุณมีคำตอบสำหรับคำถามข้อใดข้อหนึ่งของคุณแล้ว

ในหน้าMSDNมีเส้นตรงหลังจากคำพูดของคุณที่อธิบายสิ่งนี้:

โครงสร้างไวยากรณ์พื้นฐานสำหรับ CTE คือ:

ด้วย 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

โดยทั่วไปฉันต้องการตั้งชื่อคอลัมน์ภายใน CTE แทนที่จะเป็นWITH CTE (xxx) AS1ส่วนข้อเนื่องจากคุณจะไม่ผิดชื่อและเนื้อหาในคอลัมน์โดยไม่ตั้งใจ

ยกตัวอย่างเช่นตัวอย่างต่อไปนี้:

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

สิ่งนี้แสดงอะไร? มันแสดงให้เห็นเนื้อหาของyคอลัมน์ภายใต้หัวข้อxและเนื้อหาของคอลัมน์ภายใต้หัวข้อxy

ด้วยการทำให้เป็นจริงนี้ฉันไม่เคยระบุชื่อคอลัมน์ใน(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;

สิ่งนี้คล้ายกับนิยามของมุมมองหรือตารางที่ได้รับซึ่งคุณสามารถระบุรายการชื่อคอลัมน์ได้เช่นกัน

รายการคอลัมน์ : เมื่อคุณมีการคำนวณที่ซับซ้อนมากมายการหาชื่อได้ง่ายกว่าเพราะพวกมันไม่กระจัดกระจายผ่านซอร์สโค้ด และจะง่ายกว่าถ้าคุณมี curs แบบเรียกซ้ำและคุณสามารถกำหนดชื่อต่างกันสองชื่อให้กับคอลัมน์เดียวกันใน # 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.