SQL Server上的模块化级联删除

时间:2014-01-27 16:27:38

标签: sql-server sql-server-2008-r2 modularity cascading-deletes

我有一张桌子(让我们称之为tMainTable),这张桌子目前被其他许多桌子引用(而且它们的数量可能随着时间的推移而增长)。

由于循环检测,其中一些表不能只有ON DELETE CASCADE子句。

我知道如果我在ON DELETE CASCADE上写INSTEAD OF触发器,我可以删除tMainTable子句。

但是,每当一个新表被添加为tMainTable的后代时,就必须编辑触发器(作为“模块化”瘾君子)只是蹩脚(而且有风险 - 想象一个没有经验的用户只是打破了整个事情)。

所以我正在认真寻找另一种方法。

我只是想到了一些事情。

如果我创建一个表tMainTableID,只保留ID tMainTable AFTER的副本(使用INSTEAD OF触发器进行插入的副本),该怎么办?

然后,我在tMainTable上创建tMainTableID触发器,首先删除tMainTable的相应行,然后删除tMainTableID的实际行。

如果我这样做,我应该有一些非常好用的东西:一个表(tMainTable)我可以“附加”AFTER DELETE触发器来删除任何需要在行{{{{{{ 1}}实际上已删除。

-- Made by ME on 2014-01-27
CREATE TRIGGER tMainTableID_AFDEL_tTableChild01
AFTER DELETE
ON tMainTableID
AS
BEGIN
    DELETE T
    FROM deleted AS D
    INNER JOIN tTableChild01 AS T ON (
        T.RefToMainID = D.ID
    )
END
GO

-- Made by ME on 2015-01-01
CREATE TRIGGER tMainTableID_AFDEL_tTableChild02
AFTER DELETE
ON tMainTableID
AS
BEGIN
    DELETE T
    FROM deleted AS D
    INNER JOIN tTableChild02 AS T ON (
        T.RefToMainID = D.ID
    )
END
GO

-- Made by Iamun Kompetent on 2016-01-01
CREATE TRIGGER tMainTableID_AFDEL_tTableChild03
AFTER DELETE
ON tMainTableID
AS
BEGIN
    DELETE T
    FROM inserted AS D
    INNER JOIN tTableChild02 AS T ON (
        D.ID = D.ID
    )
END
GO  

你觉得这种方法有什么问题,甚至更好,你知道更好的方法来实现模块化吗?

- 编辑:简单的例子

create table tTest20140128 (
    id int not null primary key
)
go

create table tTest20140128_Child01 (
    id int not null primary key references tTest20140128(id) on delete no action
)
go

create table tTest20140128_Child02 (
    id int not null primary key references tTest20140128(id) on delete no action
)
go

insert tTest20140128 values (1), (2), (3)
insert tTest20140128_Child01 values (1), (2), (3)
insert tTest20140128_Child02 values (1), (2), (3)
go

delete from tTest20140128 -- Error
go

-- table for holding copies of ids
create table tTest20140128_ID (
    id int not null primary key references tTest20140128(id) on delete no action
)
go

insert tTest20140128_ID
select id from tTest20140128
go

-- trigger that keeps tTest20140128_ID up to date for new ids
create trigger tTest20140128_AFINS
on tTest20140128
after insert
as
begin
    insert tTest20140128_ID
    select id from inserted
end
go

-- Instead of delete (keeps tTest20140128_ID up to date for deleted ids)
create trigger tTest20140128_IODEL
on tTest20140128
instead of delete
as
begin
    delete ID
    from deleted AS D
    inner join tTest20140128_ID AS ID ON (
        ID.id = D.id
    )

    delete from T
    from deleted AS D
    inner join tTest20140128 AS T on (
        T.id = D.id
    )
end
go

-- Sorta "attching listeners to event" 
-- tTest20140128_Child01
create trigger tTest20140128_tTest20140128_Child01
on tTest20140128_ID
after delete
as
begin
    delete T
    from deleted as D
    inner join tTest20140128_Child01 AS T on (
        T.id = D.id
    )
end
go

-- tTest20140128_Child02
create trigger tTest20140128_tTest20140128_Child02
on tTest20140128_ID
after delete
as
begin
    delete T
    from deleted as D
    inner join tTest20140128_Child02 AS T on (
        T.id = D.id
    )
end
go

-- New tests
insert tTest20140128 values (4), (5), (6)
insert tTest20140128_Child01 values (4), (5), (6)
insert tTest20140128_Child02 values (4), (5), (6)
go

select COUNT (*) as [COUNT after insert] from tTest20140128
go

delete from tTest20140128 -- No Error
go

select COUNT (*) as [COUNT" after delete] from tTest20140128
go

drop table tTest20140128_ID
drop table tTest20140128_Child02
drop table tTest20140128_Child01
drop table tTest20140128

1 个答案:

答案 0 :(得分:0)

创建表格听起来不必要......但是你的INSTEAD OF触发器听起来是个好主意:

如何在tMainTable上创建INSTEAD OF触发器,首先“删除任何需要在tMainTable行之前删除的内容”,然后“删除tMainTable的实际行”?