7
While @@Fetch_Status = 0
Begin
    INSERT INTO  [server].MyDatabase.dbo.Mytabletobeinserted (

    UPC,
    Sale_date)  
    VALUES(
    @UPC,
    @Sale_date)

    'Inserting the error trapping here'

    IF (@@ERROR <> 0)
    BEGIN
        ROLLBACK TRANSACTION;
        RETURN;
    END 

    Update t_sale_from_pos
    set been_sent = 'y' 
    where UPC = @UPC and sale_date=@sale_date

    Fetch Next from CursorSale
    into 
    @UPC,
    @Sale_date
end
close CursorSale

deallocate CursorSale

このストアド プロシージャはスケジューラで毎日実行され、データはネットワーク経由で渡されます。このストアド プロシージャを実行すると、実行プロセス中に突然ネットワーク タイムアウトが発生します。これにより、すべての行が実行され、ネットワーク経由で他のサーバーに送信されます。


今、私の問題は次のとおりです。

  • これは、ループ内でロールバック トランザクションを呼び出すデータにどのように影響しますか?
  • すべての行を再度読み取り、挿入のためにサーバーに送信しますか、それとも実行中に失敗した行を読み取るだけですか?

アドバイスが必要です。ありがとう

4

4 に答える 4

6

begin distributed transactionを試すことができます。分散トランザクションは 2 つ以上のサーバーにまたがるように設計されているため、この場合には分散トランザクションが最適です。トランザクションを使用すると、システムがクラッシュしたり、停電が発生したりしても、システムは一貫した状態に回復できます。

BEGIN DISTRIBUTED TRANSACTION;

BEGIN TRY
    //Your code here to create the cursor.
    While @@Fetch_Status = 0
    Begin
         INSERT INTO  [server].MyDatabase.dbo.Mytabletobeinserted(UPC,Sale_date)  
                                                          VALUES(@UPC,@Sale_date)

         Update t_sale_from_pos
         set been_sent = 'y' 
         where UPC = @UPC and sale_date=@sale_date

         Fetch Next from CursorSale into @UPC,@Sale_date
    END
    close CursorSale

    deallocate CursorSale
END TRY
BEGIN CATCH
    close CursorSale

    deallocate CursorSale

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO

実際、分散トランザクションではカーソルを使用する必要はありません。あなたの場合、一時テーブルを作成して同時実行の問題を回避することも検討することをお勧めします。この理由は、insert ステートメントに時間がかかり、データの挿入中に別のユーザーによってテーブルが更新され、その後に発生した update ステートメントが間違った行を更新する可能性があるためです。

BEGIN DISTRIBUTED TRANSACTION;

BEGIN TRY
    CREATE TABLE #LocalTempTable(UPC int,Sale_date datetime)
    INSERT INTO #LocalTempTable(UPC,Sale_date)
    SELECT UPC,Sale_date 
    FROM YourTable

    INSERT INTO [server].MyDatabase.dbo.Mytabletobeinserted(UPC,Sale_date)  
    SELECT UPC,Sale_date 
    FROM #LocalTempTable

    Update t_sale_from_pos
    set been_sent = 'y' 
    where EXISTS (SELECT *
                  FROM #LocalTempTable
                  WHERE #LocalTempTable.UPC = t_sale_from_pos.UPC 
                        AND #LocalTempTable.Sale_date  = t_sale_from_pos.Sale_date)

END
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO
于 2013-06-22T09:11:30.083 に答える
0

各レコードをループする代わりに、チャンクで挿入することをお勧めします。一度に 5000 レコードのように、自動化されたジョブであれば、これは実現可能です。

ここに私が見つけたリンクがありますが、基本的には、上記のループで毎回トップ 5000 を実行することになります。挿入のために各レコードでカーソルを実行するジョブがある場合、おそらく非常に高価になると思います。

http://social.msdn.microsoft.com/Forums/sqlserver/en-US/1b3dbf8d-252f-43c4-80d6-d5724fe912b4/how-to-insert-rows-in-chunk-size

于 2013-06-27T03:15:40.470 に答える