WITH CTE ve WITH CTE (<column_names>) arasındaki fark nedir?


11

MSDN'de Ortak Tablo İfadelerini Kullanma bölümünde gösterildiği gibi , bir CTE'yi şu şekilde tanımlayabilirsiniz:

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

ve şöyle kullanın:

SELECT <column_list> FROM expression_name;

Diyelim ki aşağıdaki 2 CTE'm var

with cte1 as(
select name from Table1
)

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

Bir sorgu, iç sorgu aynı olduğundan her iki CTE için aynı sonuçları verir. Bu ikisi arasındaki tek fark, cte2'nin(name) bildiriminde tanımlanmış sütun adına ( ) sahip olmasıdır .

Her iki CTE'yi yürüttüğümde, yürütme planında herhangi bir fark görmüyorum.

Sadece merak ediyorum:

  • CTE tanımında herhangi bir sütun adı belirtmezsem ne fark eder?
  • CTE oluştururken neden sütun adlarını belirtmem / vermemeliyim?
  • Sorgu yürütme planını şans eseri etkiler mi? (Gördüğüm kadarıyla, hiçbir fark yaratmıyor.)

Yanıtlar:


25

Sorularınızdan birinin neredeyse cevabı zaten var.

Gelen MSDN sayfasında, bu açıklar senin alıntı hemen sonra bir çizgi vardır:

Bir CTE için temel sözdizimi yapısı:

İfade_adı [(sütun_adı [, ... n])] İLE

GİBİ

(CTE_query_definition)

Sütun adları listesi, yalnızca sorgu tanımında sonuçta elde edilen tüm sütunlar için ayrı adlar sağlanıyorsa isteğe bağlıdır.

(Vurgu eklendi)

Bu, birkaç durumda sütun adlarını belirtmeniz gerektiği anlamına gelir:

  • Bu işe yarar:

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

    WITH [test_table]  
    AS
    (
        SELECT 
            1 as [NoName]
          , CAST('1' AS CHAR(1)) as [CAST]
          , dbo.CastToChar(1) as [Function]
    )
    SELECT * FROM [test_table];
    
  • Ancak bu, sütunlar için farklı adlara sahip olmadığı için olmaz:

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

1
temel olarak, sütun içermeyen sürüm, SQL'in sütun adlarını sorgudan "çıkarması" dışında sütun içeren sürümle aynıdır.
KutuluMike

10

Anekdotsal olarak, CTE içindeki sütunları WITH CTE (xxx) AS1 yan tümcesi yerine adlandırmayı tercih ederim, çünkü adları yanlışlıkla sütun içeriğine karşı asla eşleşmezsiniz.

Örneğin aşağıdaki örneği ele alalım:

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

Bu ne gösteriyor? Bu içeriğini gösterir ybaşlığı altında sütununun xve içeriklerini xbaşlığı altında sütuna y.

Bu gerçekleştirme ile, yan tümcesinde sütun adlarını asla belirtmiyorum (xxx) AS, bunun yerine böyle yapıyorum:

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

Bu, sütun tanımlarının ne olduğu hakkındaki tüm şüpheleri ortadan kaldırır.

Tamamen ilgisiz bir yan notta; Her zaman nesne adlarını başvururken şema adı belirtmek ve noktalı virgülle ile ifadeleri bitirmek .


7

Sonuçta her sütun geçerli bir ada ihtiyaç duyar ve iki şekilde atayabilirsiniz:

  1. Sütun listesi

    ;WITH cte (foo)
    AS
    ( select col from tab )
    select foo from cte;
  2. Orijinal sütun adlarını veya takma adlarını kullanma

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

Her iki yaptığınızda takma ve sütun listesi

  1. Hem sütun listesi hem de takma adlar

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

Bu, sütun adlarının bir listesini de belirtebileceğiniz bir Görünüm veya Türetilmiş Tablo tanımına benzer.

sütun listesi : Çok sayıda karmaşık hesaplamanız olduğunda, adı belirlemek daha kolaydır, çünkü bunlar kaynak koduna dağılmamıştır. Yinelemeli bir cte'niz varsa ve # 3'te aynı sütun için iki farklı ad atayabilirsiniz.

orijinal ad / takma adlar : Yalnızca bir hesaplama yaparsanız veya bir sütunu yeniden adlandırmak istiyorsanız / gerekirse takma ad atamanız gerekir


1
"fark etmesi daha kolay" belki biraz özneldir. Satır başlangıcında, sütun başına diğer adların satır SomeAlias = SomeFunction(SomeColumn)başına yalnızca bir sütun tanımıyla olmasını tercih ederim . Bu, aradığınızı bulmak için sütun listesinin sol tarafında basit bir taramaya izin verir.
Max Vernon

1
@MaxVernon: Bu doğru ve birden çok satıra yayılan hesaplamalar arasına boş satır eklemek de yardımcı oluyor. Aslında ben de sütun listesini de
atlıyorum

2
Görüşlerinden bahsettiğiniz komik. Bir görünümü tanımlarken olduğu gibi, görünüm adından sonra sütun listesini hiç kullanmadım CREATE VIEW SomeView (ColA, ColB, …) AS …. Şimdi bunu gündeme getirdiğinize göre, senaryoları düşünüyorum 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);- hata ayıklamak için ne büyük bir mutluluk!
Andriy M
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.