web-dev-qa-db-ja.com

制約が原因でDELETEが失敗するかどうかをテストする方法はありますか?

実際に削除を実行せずに、DELETEが制約違反に遭遇するかどうかを予測できるようにしたいと思います。

これを行うための私のオプションは何ですか? DELETEの「ドライラン」を実行する簡単な方法はありますか?

10
Jay Sullivan

すべての削除が成功した場合にのみすべての削除を処理することが目標である場合は、TRY/CATCHを使用しないでください。

BEGIN TRANSACTION;
BEGIN TRY
  DELETE #1;
  DELETE #2;
  DELETE #3;
  COMMIT TRANSACTION;
END TRY
BEGIN CATCH
  ROLLBACK TRANSACTION;
END CATCH

1つ以上が失敗してもすべての成功した削除を成功させることが目的である場合は、個別のTRY/CATCHを使用できます。

BEGIN TRY
  DELETE #1;
END TRY
BEGIN CATCH
  PRINT 1;
END CATCH

BEGIN TRY
  DELETE #2;
END TRY
BEGIN CATCH
  PRINT 1;
END CATCH
24
Aaron Bertrand

1つのオプションは、トランザクションを開始し、削除を実行してから、常にロールバックすることです。

begin tran

delete Table1 where col1 = 1

-- Test whether it is there
select * from Table1 where col1 = 1

rollback tran

-- Confirm that it is still there
select * from Table1 where col1 = 1
6
GaTechThomas

Aaron Bertrandが提供するソリューションをいくつかのコードで改善したいと思います。テーブルの要素を追加したり、例外を管理して失敗を無視したり、エラー後にプロセスを停止したりする場合です。

これはテーブルからレコードを選択し、例外なくそれらを削除しようとします:

DECLARE @MaxErrors INT
SET @MaxErrors = 5;    // Setting 0 will stop process after the first error!

SELECT
    [Id]
    , ROW_NUMBER() OVER (ORDER BY Id ASC) AS [Index]
INTO #DeletingItems
FROM myTable

DECLARE @Current INT, @Max INT, @Id INT, @TotErrors INT
SELECT
    @Current = 1
    , @TotErrors = 0
    , @Max = MAX([Index])
FROM #DeletingTable

WHILE @Current <= @Max
BEGIN
    SELECT
        @Id = [Id]
    FROM #DeletingItems
    WHERE
        [Index] = @Index;

    BEGIN TRANSACTION;    
    BEGIN TRY    
        DELETE FROM myTable WHERE [Id] = @Id;

        COMMIT TRANSACTION;    
    END TRY    
    BEGIN CATCH    
        ROLLBACK TRANSACTION;

        SET @TotErrors = @TotErrors + 1;

        IF @TotErrors > @MaxErrors
            BREAK;
    END CATCH

    SET @Current = @Current + 1;
END
0
MAXE