SQL повлиял на количество строк в пакете операторов - PullRequest
2 голосов
/ 16 марта 2012

Я выполняю следующую серию операторов в цикле, пока число затронутых строк не вернется к 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;

1 Ответ

0 голосов
/ 17 марта 2012

Вы можете попробовать включить NOCOUNT перед первой INSERT, а затем сбросить ее обратно:

DECLARE @ScopeTable TABLE (  KeyField bigint,  PRIMARY KEY ( KeyField ) )

<b>SET NOCOUNT ON</b>

INSERT INTO @ScopeTable
SELECT DISTINCT DocumentID FROM [CurrentArchive].[dbo].[ItemData]
WHERE DocumentID IS NOT NULL 

<b>SET NOCOUNT OFF</b>

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)
...