2011-06-30 4 views
1

次のサンプルコードをSQL Serverで実行すると、newid()が結合後にマテリアライズされ、row_number()が結合前にマテリアライズされることがわかります。誰もがこれを理解していて、それを回避する方法があるのでしょうか?なぜnewid()はクエリの最後に現れますか?

declare @a table (num varchar(10)) 
insert into @a values ('dan') 
insert into @a values ('dan') 
insert into @a values ('fran') 
insert into @a values ('fran') 

select * 
    from @a T 
      inner join 
     (select num, newid() id 
      from @a 
      group by num) T1  on T1.num = T.num   

select * 
    from @a T 
      inner join 
     (select num, row_number() over (order by num) id 
      from @a 
      group by num) T1  on T1.num = T.num 
+0

私はCTEを見ません...? –

+0

@pst:それは「匿名」だからです。 :-) –

答えて

0

私は問題が何であるかを確認しています。最初のサブクエリのT1をマテリアライズ:

SELECT num, ROW_NUMBER() OVER (ORDER BY num) 
    FROM @a 
    GROUP BY num; 

次の2つの行を取得:

dan 1 
fran 2 

を今すぐNUM = NUM​​のに対して、あなたは4行、それぞれ異なった値の2を取得することを参加。あなたの実際の目標は何ですか? ROW_NUMBER()を外部に適用する必要がありますか?

マテリアライゼーションの順序は、オプティマイザによって異なります。他の組み込み関数(RAND()、GETDATE()など)も同様に一貫性のないマテリアライゼーション動作をすることがわかります。それほどあなたはそれについて行うことはできませんし、彼らはそれを "修正"するつもりはありません。

EDIT

新しいコードサンプル。 @aの内容を#tempテーブルに書き込んで、一意のnum値ごとにNEWID()割り当てを「実現」します。

SELECT num, id = NEWID() 
    INTO #foo FROM @a GROUP BY num; 

SELECT a.num, f.id 
    FROM @a AS a 
    INNER JOIN #foo AS f 
    ON a.num = f.num; 

DROP TABLE #foo; 
+0

これは、 'row_number()'ではどのように動作するのですが、 'newid()'ではどのように動作するのかを見ていきます。基本的に、 'newid()'を 'row_number()'のように動作させるためには、何を書く必要がありますか? – Milimetric

+0

NEWID()は問合せのどこにあってもマテリアライズされているようです。行を挿入して重複を防ぐときにGUIDを作成するのはなぜですか?異なるnum値に対してNEWID()を実際に実現する唯一の方法は、まずそれらを書き留めることです。 2番目のコードサンプルを追加します。 –

+0

ええ、私の場合、一時テーブルは非効率的です。だから奇妙ですが、私には解決策がないと思います。あなたが正しいかもしれないので、私はあなたのことを受け入れるでしょう、これは私たちが得られる最も近いものです。 – Milimetric

1

私も同様の問題があり、「内部結合」が問題であることがわかりました。私は "左の結合"を使用することができました...

+0

あなたの主張を証明する2つのステートメントを投稿できますか?もし私が正しければ、左への結合によってnewid()がより早く現実化されると言っているのでしょうか?それは正しいとは言えません。あいにく残念ながら、ここでは左結合はオプションではありません。 – Milimetric

関連する問題