2011-01-26 24 views
27

BY ORDERせずに私はSQL Server 2005のROW_NUMBER()

DECLARE @IDOffset int; 
SELECT @IDOffset = MAX(ISNULL(ID,0)) FROM TargetTable 

INSERT INTO TargetTable(ID, FIELD) 
SELECT [Increment] + @IDOffset ,FeildValue 
FROM SourceTable 
WHERE [somecondition] 

TargetTable.ID私はオートへの道を見つけなければならない理由は、ID列、ではありませんを使用して別のものに一つのテーブルから挿入しようとしています - それを自分で増やしてください。

私は、カーソルを使用することができ、またはID列とFieldValueフィールドを持つテーブル変数を作成し、それを移植してからinsert into...selectで使用することができますが、これはあまり効率的ではありません。 ROW_NUMBER関数を使ってインクリメントしてみましたが、実際にはSourceTableの正当なORDER BYフィールドがなく、SourceTableの元の順序を保持したいと考えています(可能な場合)。

誰もが何か示唆できますか?

+2

ソーステーブルにクラスタ化インデックスとは何ですか?私はあなたが「SourceTableの元の順序」と言うとき、それがあなたが話しているものだと仮定していますか?それがヒープの場合、特別な順序はありません。 –

答えて

70

次のように明示的な順序を指定しないようすることができます

INSERT dbo.TargetTable (ID, FIELD) 
SELECT 
    Row_Number() OVER (ORDER BY (SELECT 1)) 
     + Coalesce(
     (SELECT Max(ID) FROM dbo.TargetTable WITH (TABLOCKX, HOLDLOCK)), 
     0 
    ), 
    FieldValue 
FROM dbo.SourceTable 
WHERE {somecondition}; 

はしかし、それは単に任意の元のデータの順序は保持されますを保証するものではありません発注と を指定しないようにする方法であることに注意してください。外部クエリのORDER BYのように、結果を順序付ける原因となる他の要因があります。これを完全に理解するには、「特定の方法で注文されていない」という概念が、「元の注文を保持する」(特定の方法で注文されている!)という概念と同じではないということを認識しなければなりません。純粋なリレーショナルデータベースの観点からは、後者の概念は存在しません。定義によって(これに違反するデータベース実装が存在する可能性がありますが、SQL Serverはその1つではありません)。

ロックヒントの理由は、実行するクエリの部分の間で、使用する予定の値を使用して他のプロセスが挿入されることを防ぐためです。

注:多くの人が(SELECT NULL)を使用して、「ウィンドウ関数のORDER BY句に許可されている定数はありません」という制限を回避します。何らかの理由で、私は1よりもNULLを好む。

また、ID列がはるかに優れているため、代わりに使用する必要があります。並行性がテーブル全体を排他的にロックするのは良くありません。過小評価

+0

@Emtucifor:最初の作品は大丈夫です。 2番目の場合は、いずれの場合も1行の結果が返されます。テーブルが空の場合、NULLを返します。したがって、副選択の必要はなく、MAX()ではISNULL()を使用しますが、内部では使用しません。私はどういうわけかそれを最初に却下することができました。実際、私はそれをあまり考えていないかもしれません。単なる偶然の一致は、私がここで誰かのポストを読むときには別のことを学ばせました(今はどちらを覚えていないか)。私は訂正を掲載する前にそれをチェックした。なぜそれは良いですか?まあ、見た目が単純で、読むのも簡単だと思います。 –

+0

外部クエリに 'ORDER BY'節がある場合、または他のエッジケースではこれが正しいとは限りません:http://stackoverflow.com/q/18961789/521799 –

+0

@LukasEder私の答えは正しいですしかし、おそらくそれは完全ではないかもしれませんでした。誰かが "元の注文を保存する"ことを探していて、これがSQL Serverのナンセンスのコンセプトであることに気付かなかった場合、このコードを使用して取得しようとする可能性がありますが、失敗する可能性があります。私はこの面に対処するために私の答えを更新しました。 – ErikE

2

あなたはこのようorder by (select null)を使用して順序を無視することができます。

declare @IDOffset int; 
select @IDOffset = max(isnull(ID, 0)) from TargetTable 

insert into TargetTable(ID, FIELD) 
select row_number() over (order by (select null)) + @IDOffset, FeildValue 
    from SourceTable 
where [somecondition] 
+1

5年前の回答と比べると、これは何を追加するのでしょうか?新しいアプローチはありません。新しい説明はありません。それは新しいものを提供しません。 – hvd