2017-08-11 19 views
0

次のクエリの特定の部分がどのように機能するのかの説明や説明が見つかりません。T-SQL WITH ... UPDATEの例の説明

問合せ:

;WITH ToUpdate AS (
    SELECT Id, 
      Foo, 
      FIRST_VALUE(Foo) OVER (ORDER BY Id) + 
       ROW_NUMBER() OVER (ORDER BY Id) - 1 AS newFoo 
    FROM mytable 
    WHERE Bar= 1 
     AND Id >= 111 
) 
UPDATE ToUPDATE 
SET Foo = newFoo 

これは、以下の問題に似ている別の質問への答えとしてSOユーザーGiorgos Betsosから来ました。

  • Bar=1で、IDでId >= 111
  • ための行とすべての行を取る:

    Id Foo Bar 
        2  5 1 
        3  6 1 
    13 111 22 
    111  7 1 
    122 16 1 
    154 17 1 
    176 18 1 
    

    致しておりますが、クエリを使用したい:

    たちは、このような表を考えてみましょう昇順

  • すべて更新Foo新しい値が前の行の値と同じになるように更新する1で、だから、結果表は次のようになりますId = 111

で行から始まる:

Id Foo Bar 
    2  5 1 
    3  6 1 
13 111 22 <-- not affected 
111  7 1 
122  8 1 
154  9 1 
176 10 1 

は今、クエリでも例がここに与えられた、素晴らしい作品:EXAMPLE

しかし、WITH/UPDATEの組み合わせがなぜ機能するのか分かりません。

基本となるテーブルが更新されるのはなぜですか?一見すると、WITHで返されたビュー/一時テーブルだけが更新され、基になるテーブルは変更されずに残っていると考えました。

答えて

5

CTE内の列を更新すると、SQL Serverはその列を元のテーブルに戻します。この場合、mytableテーブルにはFooという列があるため、実際にはmytableテーブルに更新されます。

ちなみに、CTEはどのような種類の一時的なテーブルでもなく、ビューでもありません。これは、SQLコード/機能をラップする便利な方法です。実際には、CTEは実際にはUPDATEという典型的な文にコンパイルされ、EXPLAINを実行して自分自身を説得することができます。

UPDATEのCTEのうち、物理テーブルに戻ってトレースできない列を含むものを実行しようとすると、何が起こるのか不思議に思うかもしれません。この場合、次のようなエラーが表示されます。

ビューまたは関数 'cte'の更新または挿入に、派生フィールドまたは定数フィールドが含まれていないため、失敗しました。

エラーメッセージにはすべて記載されています。物理テーブルに実際に存在しない列を更新しようとしましたが、SQL Serverは更新を拒否して抗議しました。

+0

良い説明、感謝のTim – Rob212