有没有一种方法可以测试DELETE是否会由于约束而失败?


10

我希望能够预测DELETE是否会遇到约束违例,而无需实际执行删除操作。

我有什么选择呢?有没有简单的方法可以对DELETE进行“空运行”?


您是要尝试仅防止该语句的异常发生,还是要简化包含此删除操作的较大批处理中的错误处理?
亚伦·伯特兰

3
您可以检查是否存在FK,然后运行SELECT语句检查值吗?
SQLRockstar 2012年

Aaron:我们需要在单独的事务中运行一批几个DELETE。如果其中一个失败,则其他人已经提交。(我知道设计从一开始就很糟糕,但这不是我的应用程序,并且没有改变。)目前最好的解决方法听起来像是进行干式检查,以查看DELETE是否会失败。
杰伊·沙利文

仍然不确定我是否理解。您是要让其余的删除成功完成,还是要先检查所有删除都将成功完成,还是都不应该进行?
阿龙贝特朗

亚伦:对不起,我没有说清楚,但是的,我正在尝试确保它们全部成功,或者没有一个成功。
杰伊·沙利文

Answers:


24

如果您的目标是仅在所有删除均成功的情况下处理所有删除,为什么不使用TRY / CATCH:

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

如果目标是即使一个或多个失败都会允许所有成功的删除成功,则可以使用单独的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

6

一种选择是开始事务,运行删除,然后始终回滚:

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

1
如果删除成功,请再次运行?如果删除非常昂贵怎么办?如果删除失败,那该怎么办?您已完成一个删除和两个选择。如何决定是否继续进行下一个删除?
阿龙贝特朗

1
如果这些是要求的一部分,则应进行处理。这个答案是关于“简单的'空转'”的。
GaTechThomas 2012年

好吧,它们不是在您第一次提交答案时出现的,但是现在已经澄清了。
亚伦·伯特兰

4
@GaTechThomas Aaron做出了很多贡献,所以他有时很简短,但我相信他的意图不是要变得好斗。我在The Heap中对此进行了讨论,我也非常感谢有机会与您一起讨论。
杰克说尝试topanswers.xyz 2012年

1
@JackDouglas我已经阅读了您引用的The Heap评论,并理解了这一点。社区的评论是合理的,除了我被用来指出他的侵略行为的小丑这一部分。我不明白自己是个好斗的人。我对当时提出的问题发表了合法的答案。它并没有要求生产质量-有时您只需要快速简便即可。因此,根据我的回答,我会提出尖锐的问题。看来他在he毁我的回答,以便他会被选中。我们应该把这个线程带到其他地方吗?
GaTechThomas 2012年

0

我想用一些代码来改进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

1
为什么?与公认的答案相比,这有什么改进?
ToolmakerSteve
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.