我有一个包含树状结构的表
采取以下形式:
-nodeID,fkID,parentNode
(如果父节点是根节点,则为NULL,如果是子节点,则为父节点的nodeID) (如果不是根,则fkID为NULL)
fkID是一个FK,当在另一个表中删除时,将其删除级联到此表。但是,此级联删除仅引用根节点。在数据库中存在另一个约束,其中除非首先删除其子节点,否则无法删除根节点。但是我不能在自引用约束上级联,因为SQL SERVER不会给我这个选项。我认为一个触发器可能是一个很好的解决方案但是我必须首先递归树并在父母之前删除孩子。这需要我在级联发生之前删除。有没有办法做到这一点?
我在以下触发器上遇到以下错误
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER dbo.deleteChildren
ON dbo.faultTreeNodes
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON;
-- Insert statemets for trigger here
END
GO
ERROR:
CANNOT CREATE TRIGGER INSTEAD OF DELETE BECAUSE THIS
TABLE HAS A FOREIGN KEY WITH A CASCADING DELETE
提前感谢您的任何建议或帮助!
答案 0 :(得分:1)
即使我已经投票结束duplicate,我想我会发布一个答案,因为,在第二个想法,重复问题的答案最终在编辑问题后有点混乱,以及最近添加的声明
我猜你只需要从类别中的递归外键中删除ON DELETE CASCADE标志。来自CAT_SCH的外键上的CASCADE标志无关紧要
实际上不是真的(SQL Server会在删除时引发错误,因为一个字段上的cascade
会与另一个字段上的no action
冲突。)
主要观点仍然存在:
on delete no action
。instead of delete
触发器,按顺序删除所需的子项,然后删除“主”记录本身。E.g。 (SQL Fiddle):
create table main(id int not null primary key);
create table nodes (
nodeID int not null primary key,
fkID int null foreign key references main(id),
parentID int null foreign key references nodes(nodeID)
);
create trigger dlt on main
instead of delete
as
begin
declare @to_delete table (nodeID int not null, level int not null, primary key(level, nodeID));
begin tran;
with cte as (
select n.nodeID, 0 as level
from nodes n inner join deleted d on n.fkID = d.id
union all
select n.nodeID, level + 1
from nodes n inner join cte c on n.parentID = c.nodeID
)
insert into @to_delete(nodeID, level)
select nodeID, level
from cte;
declare cur cursor
local
forward_only
read_only
for
select distinct level from @to_delete order by level desc;
open cur;
declare @cur_level int;
fetch next from cur into @cur_level;
while @@fetch_status = 0
begin
delete from nodes
from nodes n inner join @to_delete d on n.nodeID = d.nodeID
where d.level = @cur_level;
fetch next from cur into @cur_level;
end;
close cur;
deallocate cur;
delete from main from main m inner join deleted d on m.id = d.id;
commit tran;
end;