私は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の元の順序を維持したい場合(可能な場合)。
誰でも何か提案できますか?
次のように明示的な順序を指定しないようにすることができます。
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列ははるかに優れているため、代わりに使用する必要があると思います。同時実行がテーブル全体を排他的にロックするのは良くありません。控えめな表現。
次のように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]