问题
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