如何尝试删除记录而不终止错误

时间:2011-10-31 19:44:01

标签: sql sql-server tsql sql-server-2008-r2

我有一个表在其他几个表中用作外键。如果只在一个特定的表中引用该表,我希望允许删除并在删除时级联。但是,如果其他表中存在引用,则删除应该失败。

我想通过尝试删除每条记录来测试我的数据集的引用完整性。除最后一个记录外,不应删除任何记录。但是,当我尝试删除每条记录时,它会出错(如预期的那样)并终止语句的其余部分。

如何编写试图删除表中每条记录的脚本,而不是在第一次错误时终止该语句?

亲切的问候,

下流

编辑:

我想要做这样的事情的原因是因为业务用户添加了大量重复数据(即:搜索某人并单击“添加为新”而不是“选择”)。现在我们可能有10个人,只有一个名字,与其他表没有关系。我希望这可以澄清任何混乱。

4 个答案:

答案 0 :(得分:3)

我玩弄了不同的想法。这是最直接的方式。但是,这是非常昂贵的。同样,这是尝试删除未使用的重复数据。 1,000条记录花了8分钟。谁能想到一种更有效的方法呢?

DECLARE @DeletedID Int

DECLARE ItemsToDelete SCROLL CurSor For
SELECT ID FROM ParentTable

Open ItemsToDelete

FETCH NEXT FROM ItemsToDelete INTO @DeletedID
     While @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY
        --ATTEMPT TO DELETE
        DELETE FROM ParentTable WHERE ID = @DeletedID;
    END TRY 

    BEGIN CATCH
        --DO NOTHING
    END CATCH

        --FETCH NEXT ROW
    FETCH NEXT FROM ItemsToDelete INTO @DeletedID
END


Close ItemsToDelete

Deallocate ItemsToDelete

答案 1 :(得分:1)

带上一粒盐:我实际上不是DBA,从未使用过SQL Server。但是:

你实际上违反了两条不同的规则:

  1. 参考约束
  2. 特定于业务(我假设)'允许删除'规则。
  3. 听起来就像设置了引用约束(在子表中)时,它们是使用选项RESTRICTNO ACTION创建的。这意味着,当存在子行时,尝试从父表中删除将导致失败。但问题是,您希望在特定的表上允许删除并传播它们(选项CASCADE)。因此,对于那些要删除的表,请更改引用约束以使用CASCADE。否则,使用(已存在的)错误阻止删除。

    至于处理突然出现的'例外'......这里有一些处理它们的方法:

    1. 预测他们。如果在一组子表中引用了键,则以 not 删除某些内容的方式编写删除。从长远来看,这显然是不可维护的,或者对于参考程度很高的表格而言。
    2. 抓住异常。我怀疑这些可以在'脚本中'捕获(特别是如果运行单个.txt类型的文件),所以你可能必须至少编写存储过程,或者从更高级别的语言运行。这里的第二个问题是你不能“跳过”错误并“继续”删除(我知道) - SQL每次都会保持失败你(...在什么等于随机行)。您必须循环遍历整个文件,按行(或可能是动态设置的行),以确保删除记录。对于小文件(相对),此可以工作。
    3. 编写一组(一组)动态语句,这些语句使用信息模式表和查找来排除“不可删除”表中包含的ID。有趣的概念,但可能很难/昂贵。

答案 2 :(得分:1)

好吧,SQL中的每个语句都被视为事务,因此,如果您尝试删除多个记录,并且在考虑完整性规则时遇到错误,则到目前为止所做的每个更改都将被回滚。您可能要做的是编写将从引用表(具有外键值(在您的情况下为T_child表)中具有值的表中删除数据的查询,然后从T_parent表中删除数据。

总计:首先检查T_child表中是否有要删除的记录,然后从T_parent表中删除记录,以避免事务失败。

希望这有帮助。

(如果我错了,请纠正我)

答案 3 :(得分:1)

这里有一些选择。你的问题有点含糊不清,所以我想先重新讨论你的用例(我会按照我的理解回答你的问题)。

使用案例

数据库由几个表T_Parent,T_Child1,T_Child2,T_Child3组成。一组完整的数据将在所有4个表中都有记录。鉴于业务需求,我们经常会得到需要在以后删除的部分数据。例如,T_parent和T_Child2可以获得数据,但不能获得TC1和TC3。

我需要能够检查部分数据,如果找到则删除所有部分数据(在我的示例中为T_Parent和T_Child 2,但它可以是TP和TC3,或其他组合)。


@ribald - 我的理解是否正确?

  • 评论我的理解,我会写出答案。如果评论不够长或不够清楚,只需编辑您的问题。
  • 你在删除方面说“级联”(这意味着SQL服务器中的一个非常具体的东西),但在你后面的描述中,它听起来更像是你想要删除所有的部分数据。
  • “Cascading”是可用的,但不是根据某些数据的条件打开和关闭的。
  • 当您说“数据集”时,您并不是指ADO.NET数据集,而只是意味着测试数据。
  • 我认为您不是在寻找一种好的测试方法,只是想确保数据的完整性。