I have the following table:
create table dbo.Link
(
FromNodeId int not null,
ToNodeId int not null
)
Rows in this table represent links between nodes.
I want to prevent inserts or updates to this table from creating a cyclic relationship between nodes.
So if the table contains:
(1,2)
(2,3)
it should not be allowed to contain any of the following:
(1,1)
(2,1)
(3,1)
I'm happy to treat (1,1) separately (e.g. using a CHECK CONSTRAINT) if it makes the solution more straightforward.
I was thinking of creating an AFTER INSERT trigger with a recursive CTE (though there may be an easier way to do it).
Assuming this is the way to go, what would the trigger definition be? If there is a more elegant way, what is it?
Note first that it is preferable to detect cycles in another environment as recursive CTEs aren't known for their good performance and neither is a trigger that would run for each insert statement. For large graphs, a solution based on the solution below will likely be inefficient.
Suppose you create the table as follows:
That would block inserts with
node_fromequal tonode_to, and for rows that already exist.The following trigger should detect cyclic references by throwing an exception if a cyclic reference is detected:
I tested this for a limited number of inserts.
And
It also detects cyclic references already present in the inserted rows if inserting more than one row at once, or if a path longer than one edge would be introduced in the graph. Going off on the same initial inserts: