web-dev-qa-db-ja.com

SQL Server 2005 ROW_NUMBER()ORDER BYなし

私は1つのテーブルから別のテーブルに挿入しようとしています

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の元の順序を維持したい場合(可能な場合)。

誰でも何か提案できますか?

29
Fragilerus

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

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など、結果を順序付けることができる他の要因があります。これを完全に理解するには、「特定の方法で順序付けされていない」という概念が「元の順序を保持する」と同じではないことを認識する必要があります(これはIS特定の方法で順序付けられています!) 。純粋なリレーショナルデータベースの観点から、後者の概念存在しない定義によると(とはいえ、これに違反するデータベース実装、SQL Serverはそれらの1つではありません)。

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

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

また、ID列ははるかに優れているため、代わりに使用する必要があると思います。同時実行がテーブル全体を排他的にロックするのは良くありません。控えめな表現。

76
ErikE

次のように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]
4
Mohammad Anini