How to prevent tree having circular references

夙愿已清 提交于 2019-12-11 17:23:37

问题


original table is more complicated but.. i got a table which stores great many trees inside like; what im looking is a nontrigger mothod like constraint or a trigger which decides to rollback very fast..

create table myTreeTable ( 
    id int not null identity(1,1),
    node varchar(80),
    parent varchar(80),
    constraint PK_mytable primary key nonclustered (node)
)

insert into myTreeTable values ('a', null)
insert into myTreeTable values ('b', 'a')
insert into myTreeTable values ('c', 'a')
insert into myTreeTable values ('d', 'a')
insert into myTreeTable values ('e', 'b')
insert into myTreeTable values ('f', 'b')
insert into myTreeTable values ('g', 'd')
insert into myTreeTable values ('h', 'f')
insert into myTreeTable values ('i', 'g')
insert into myTreeTable values ('j', 'g')

insert into myTreeTable values ('aa', null)
insert into myTreeTable values ('bb', 'aa')
insert into myTreeTable values ('cc', 'aa')
insert into myTreeTable values ('dd', 'aa')
insert into myTreeTable values ('ee', 'bb')
insert into myTreeTable values ('ff', 'bb')
insert into myTreeTable values ('gg', 'dd')
insert into myTreeTable values ('hh', 'ff')
insert into myTreeTable values ('ii', 'gg')
insert into myTreeTable values ('jj', 'gg')

what i need to prevent is an update like

update myTreeTable set parent='j' where ID=1

or an insert like

insert into myTreeTable values ('aaa', 'bbb'),('bbb', 'ccc'),('ccc','aaa')

回答1:


You can check if circular references or not by bellow query:


create trigger check_circular_ref_tgr on myTreeTable for insert, update as
begin

declare @new_node varchar(80), @new_parent varchar(80)

select @new_node=node, @new_parent=parent from inserted

with p(id) as (
select parent from myTreeTable where node = @new_parent
union all 
select parent from myTreeTable inner join p on myTreeTable.node=p.id where parent is not null)

if exists(select id from p where id=@new_node)
  raiseerror(N'circular reference error', 10, 1)

end




回答2:


You could use an Instead of Trigger to override Updates and Inserts. See this SO post: How to prevent updates to a table, with an exception for one situation




回答3:


You can add a "Descendants" table where for each pair of nodes you record whether one node is a descendant of another. It is going to have way fewer than N*N rows, because you do not need entries for nodes that are completely unrelated. (Absence of an entry means "not a descendant".)

This will give the fastest performance when searching, but it will incur a performance penalty when inserting/deleting, because you will have to update the "Descendants" table.




回答4:


You could write a function that checks to see if a insert/change will create a circular reference and call it from a CHECK CONSTRAINT.



来源:https://stackoverflow.com/questions/52666530/how-to-prevent-tree-having-circular-references

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!