我在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->start
和transaction->complete
,所以如果外键失败,事务将被中止,但这里的问题是,如果外键没有失败,那么将发生回滚,在这种情况下,记录的PRIMARY KEY
将被更改,这是不应该做的。
因此,我想要一种在交易开始前检查外键冲突的方法,而不需要实际删除记录
要实现您的要求,只需检查子表中是否存在记录,例如
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个子表,我会认真考虑总是将记录标记为已删除,而从不费心实际删除那些没有子记录的记录。一些额外的记录不太可能对数据库产生太大的影响。
实际上,根据我的经验,子表分为两类:
- 那些可以使用级联删除自动删除的
- 那些应该阻止我们删除父记录的
如果是这种情况,所需的检查应变得更易于管理。
此外,对于这些情况,我建议将删除逻辑封装在存储过程中,以便将其全部保存在一个位置,并且在未来数据库方案发生变化时易于修改。
注意:就我个人而言,我会将Deleted
列设为bit
,而不是int
,因为它更准确地反映了意图。