T-SQL删除带有对子表的多个引用的级联(或触发器)

时间:2016-09-13 01:24:15

标签: tsql triggers sql-server-2012

问题更大,但简而言之就是这样。我有两个表InvoiceAddress

Invoice表有两列:

  • BillingAddressId int,FK到Address(AddressId)
  • ShippingAddressId int,FK到Address(AddressId)

我想声明这两个与ON DELETE CASCADE的关系,但我不能,因为这会导致“多个级联路径”错误。我需要能够删除Invoice记录,并删除Address条记录。

相反,我创建了触发器:

CREATE TRIGGER [dbo].[Trigger_Invoice_DeleteAddress]
ON [dbo].[Invoice]
FOR DELETE
AS
BEGIN
    SET NoCount ON

    DELETE FROM Address 
    WHERE AddressId IN (SELECT BillingAddressId FROM deleted);

    DELETE FROM Address 
    WHERE AddressId IN (SELECT InvoiceAddressId FROM deleted);
END

这种平局不起作用,就像现在我得到的那样:

  

DELETE语句与REFERENCE约束“FK_Invoice_BillingAddress”冲突   冲突发生在数据库“示例”,表“dbo.Invoice”,列'BillingAddressId'。

也试过这个建议:

CREATE TRIGGER [dbo].[Trigger_Invoice_DeleteAddress]
ON [dbo].[Invoice]
INSTEAD OF DELETE
AS
BEGIN
    SET NoCount ON

    DELETE FROM Address 
    WHERE AddressId IN (SELECT BillingAddressId FROM deleted);

    DELETE FROM Address 
    WHERE AddressId IN (SELECT InvoiceAddressId FROM deleted);

    DELETE FROM Invoice
    Where InvoiceId in (SELECT InvoiceID from deleted);

END

这有同样的错误。

我错过了什么?

1 个答案:

答案 0 :(得分:0)

您的问题是因为您在删除子项时尝试自动删除父项。这可能无法实现,因为父母可以链接到另一张发票。无论如何,它通常不是一个好主意。你真的需要重新审视这个要求,看看它是否真的有意义。我从未见过一个系统(我曾与数百人一起工作),删除一个孩子会自动触发删除父记录。

在这种情况下,它可能特别糟糕。如果我是一名顾客,我取消了发票并在几天后去购买并且不得不重新输入我之前给你的地址信息,我会很生气,并且不太可能想要继续与公司愚蠢到做这样的事情。这是推动业务发展的要求类型。为什么你要删除发票上的地址呢?为什么你要删除发票呢?大多数会计系统永远不会删除发票。如果他们需要取消它们,那么他们会以抵消费用退出。这整个想法可以打开你的系统欺诈,因为不应该允许任何人做这样的事情,所以这真的是一个坏主意。你真的需要阅读会计标准,特别是内部控制。

在子记录消失之前,您无法删除父记录,这就是触发器不适合您的原因。

我建议您在存储过程中执行所有删除操作,或者让触发器将地址ID记录放在临时表中,然后从每五分钟运行一次的作业中删除它们。在这项工作中,您将确保检查是否有任何其他发票附加到该地址,并且仅在没有剩余发票时删除。但我仍然认为删除地址或发票是一个非常糟糕的主意。