我正在研究具有公司层次结构的树形结构。所有数据都存储在SQL Server数据库中。
数据库有两列,分别是ID和父节点ID(均为 varchar(5))。
现在,当我删除一个节点时,该节点的所有子节点(及其子节点)将保留在数据库中-未连接。我应该如何删除这些?
编辑:我正在使用https://www.codeproject.com/Articles/18378/Organization-Chart-Generator来生成图表。
答案 0 :(得分:3)
您在这里需要两件事,
第一个步骤是必需的,因此没有人可以使用其他任何方法然后再按正确的步骤删除母版。
这里是如何设置这样的系统的示例
create table test (
id int not null identity,
name varchar(10),
parentid int null,
constraint pk_id primary key (id),
constraint fk_pid foreign key (parentid) references test (id)
)
insert into test (name, parentid)
values ('master', null), ('child1', 1), ('child2', 1), ('child3', 3)
现在,当您删除例如第一行(name = master)时,sql server将停止您,并返回一条错误消息,指出违反了外键fk_pid
。
换句话说,只要母版中仍然有孩子,就再也没有人可以移除它。
现在,该程序可以删除一位主人及其所有孩子,您可以查看其他答案,然后选择最喜欢的答案。
答案 1 :(得分:2)
如果没有外键,将执行此操作。我正在创建一个名为节点的示例表,该表具有两列,即ID和Parent。在我的版本中,它们是整数,但没关系。
create table nodes(id int, parent int)
insert nodes values (1,null),(2,1),(3,1),(4,2),(5,null)
select * from nodes
结果是:
id parent
1 NULL
2 1
3 1
4 2
5 NULL
创建遍历关系的CTE
declare @target int; set @target=2
;with cte as
(
select *, 1 as depth from nodes where id=@target
union all
select nodes.*, depth+1 from nodes
join cte on cte.id=nodes.parent
)
delete nodes where id in (select id from cte)
这是结果
select * from nodes
1 NULL
3 1
5 NULL
如果您有外键,则需要从最高深度到最低深度进行仔细检查,以免出错。这样做(没有光标)
declare @temp table(id int, depth int)
declare @target int; set @target=2
;with cte as
(
select *, 1 as depth from nodes where id=@target
union all
select nodes.*, depth+1 from nodes
join cte on cte.id=nodes.parent
)
insert @temp
select id,depth from cte
while exists(select * from @temp)
begin
delete nodes from nodes
join @temp t on t.id=nodes.id
where depth=(select max(depth) from @temp)
delete @temp where depth=(select max(depth) from @temp)
end
结果相同。
答案 2 :(得分:2)
您可以使用递归过程来做到这一点:首先递归地删除节点的所有子节点,然后删除该节点。
CREATE PROCEDURE DELETE_NODE
@NODE_ID int
AS
BEGIN
declare @CHILD_NODE_ID int;
declare CHILDS cursor for select NODE_ID from MY_TABLE where PARENT_NODE_ID = @NODE_ID;
open CHILDS;
fetch next from CHILDS into @CHILD_NODE_ID;
while @@fetch_status = 0
begin
exec DELETE_NODE @NODE_ID = @CHILD_NODE_ID;
fetch next from CHILDS into @CHILD_NODE_ID;
end
close CHILDS;
deallocate CHILDS;
delete from MY_TABLE where NODE_ID = @NODE_ID
END
GO
顺便说一句,您应该在表上为其字段PARENT_NODE_ID和NODE_ID本身添加一个关系(外键),这样就不能删除使子级保持未连接状态的节点。