影響を受ける行数が 0 に戻るまで、次のステートメントのバッチをループで実行しています。
DECLARE @ScopeTable TABLE ( KeyField bigint, PRIMARY KEY ( KeyField ) )
INSERT INTO @ScopeTable
SELECT DISTINCT DocumentID FROM [CurrentArchive].[dbo].[ItemData]
WHERE DocumentID IS NOT NULL
INSERT INTO [CurrentArchive].[dbo].[ItemExtras]
SELECT TOP 1024 [ItemExtras].*
FROM [ItemExtras]
LEFT OUTER JOIN [CurrentArchive].[dbo].[ItemExtras] AS TargetTable
ON [ItemExtras].DocumentID = TargetTable.DocumentID
INNER JOIN @ScopeTable AS ScopeTable
ON [ItemExtras].[DocumentID] = ScopeTable.KeyField
WHERE (TargetTable.DocumentID IS NULL)
多くの異なるデータベースで何年も正しく機能していましたが、ある特定のデータベースで突然 38563 が返されました。これは明らかに「INSERT INTO @ScopeTable」部分の行数です。これは、他の挿入が「TOP 1024」を行うためです。
このような動作を変更できる SQL Server 設定はありますか? 0を返すことに依存するのは不適切ですか?
編集: 要求に応じて、ループを実行する (Delphi) コードを次に示します。DataAccess.NewCommand は TADOCommand を使用し、例外が発生した場合は -1 を返します。
TopClause := '';
TopCount := 2048;
Finished := false;
while not Finished do
begin
AffectedRecords := fDataAccess.NewCommand(Format(
'%s INSERT INTO %s SELECT%s%s [%s].* FROM [%s] %s',
[PreClause, QualifiedTable, ManyToOneClause, TopClause, Table, Table, WhereClause]));
if AffectedRecords >= 0 then
begin
if TopClause = '' then // first time through
Finished := true
else if AffectedRecords < TopCount then // other times through
Finished := true;
end
else
begin
// if that fails, try top 1024, 512, etc until we reach 0 or it succeeds
TopCount := TopCount div 2;
if TopCount = 0 then
begin
fTracker.LastError := 'Failed to insert items for table ' + QualifiedTable;
raise Exception.Create(fTracker.LastError);
end;
TopClause := ' TOP ' + IntToStr(TopCount);
end;
end;