【问题标题】:How to check if foreign key constraint fails when deleting record删除记录时如何检查外键约束是否失败
【发布时间】:2020-11-05 15:46:09
【问题描述】:

我在 SQL Server 中创建了一个数据库,前端是 PHP - CodeIgniter。在数据库中,我用其他表创建了多个外键。现在,当用户尝试删除记录时,而不是真正删除我想将记录标记为deleted = 1,只有在子表中没有可用的参考记录时才应该这样做。以下是示例表:

Parent_Table
Id INT(PK), Name Varchar, deleted INT

Child_Table
Id INT(PK), FK_Parent_Table_ID INT, address varchar, deleted INT

以上只是我的表格的示例。现在,每当用户尝试从父表中删除记录时,外键都会检查约束,然后删除记录,这里我希望将其标记为 deleted = 1,而不是实际删除。

我尝试过使用transaction->starttransaction->complete,所以如果外键失败,事务就会中止,但这里的问题是,如果外键没有失败,则会发生回滚,在这种情况下,记录的PRIMARY KEY将被改变不应该做的。

所以,我想要一种在事务开始之前检查外键冲突而不实际删除记录的方法

【问题讨论】:

    标签: sql sql-server codeigniter sql-server-2005


    【解决方案1】:

    要实现您的要求,只需检查子表中是否存在记录,例如

    declare @RecordToDelete int = 123;
    
    -- Delete the record if no child records exist
    delete
    from Parent_Table
    where id = @RecordToDelete
    and not exists (select 1 from Child_Table where FK_Parent_Table_ID = @RecordToDelete);
    
    -- Flag the record as deleted if child records exist
    update Parent_Table set
        Deleted = 1
    where id = @RecordToDelete
    and exists (select 1 from Child_Table where FK_Parent_Table_ID = @RecordToDelete);
    

    取决于您是否真的需要保留记录,因为您始终可以使用级联删除来创建外键。

    如果有 15 个以上的子表,我会认真考虑始终将记录标记为已删除,而从不打扰实际删除那些没有子记录的记录。一些额外的记录不太可能对您的数据库产生太大影响。


    实际上,根据我的经验,子表分为 2 类:

    • 可以使用级联删除自动删除的那些
    • 应该阻止我们删除父记录的那些

    如果是这种情况,所需的检查应该变得更易于管理。


    此外,对于这些情况,我建议将删除逻辑封装在存储过程中,以便将其全部保存在一个位置,并且在将来数据库方案发生变化时易于修改。


    注意:我个人会将Deleted 列设为bit 而不是int,因为它更准确地反映了意图。

    【讨论】:

    • 我明白你在说什么,但在我的情况下,有超过 15 个以上的表被引用,因此不太可能通过查询检查每个表。
    • @Niks 这是完全可能的,也是唯一的方法。
    • @Niks 您还需要确保您的问题包含所有相关信息,即子表的数量。
    • @Niks 。 . .这似乎回答了您实际提出的问题。如果确实如此,那么您应该接受它。如果你没有问你想要的问题,问一个新的问题。不要玩“猜我真正的问题”的游戏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-18
    • 2012-06-21
    • 2022-06-20
    • 2021-09-03
    • 1970-01-01
    • 2016-05-04
    • 2020-02-05
    相关资源
    最近更新 更多