且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何防止自引用表变成圆形

更新时间:2023-02-02 22:49:49

您可以使用 CHECK CONSTRAINT 来执行此操作,以验证管理器ID是否不是循环.检查约束中不能包含复杂的查询,但是如果先将其包装在函数中,则可以:

You can do this with a CHECK CONSTRAINT that validates manager id is not a cycle. You can't have complex queries in a check constraint, but if you wrap it in a function first you can:

create function CheckManagerCycle( @managerID int )
returns int
as
begin

    declare @cycleExists bit
    set @cycleExists = 0

    ;with cte as (
        select E.* from tblEmployee E where ID = @managerID
        union all
        select E.* from tblEmployee E join cte on cte.ManagerID = E.ID and E.ID <> @managerID
    )
    select @cycleExists = count(*) from cte E where E.ManagerID = @managerID

    return @cycleExists;

end

然后您可以使用如下约束:

Then you can use a constraint like this:

alter table tblEmployee
ADD CONSTRAINT chkManagerRecursive CHECK ( dbo.CheckManagerCycle(ManagerID) = 0 )

这将防止添加或更新记录以从任何来源创建循环.

This will prevent adding or updating records to create a cycle from any source.

重要说明:检查约束在其引用的列上得到验证.我最初将其编码为检查员工ID而不是经理ID的周期.但是,这不起作用,因为它仅在对ID列进行更改时触发.此版本之所以有效,是因为只要 ManagerID 更改,便会触发该版本.

An important note: check constraints are validated on the columns they reference. I originally coded this to check cycles on the Employee ID, rather than the Manager ID. However, that did not work because it only triggered on changes to the ID column. This version does work because it is triggered any time the ManagerID changes.