如何为ParentId / HierarchyId编写多行约束

时间:2018-10-17 12:21:34

标签: sql sql-server tsql

我有一个名为Items的表,其中包含以下三个字段:

  • 编号(int)
  • ParentId(int)
  • NodeId(HierarchyId)

    x1 + 1 <= x2

Id NodeId ParentId 2 / NULL 3 /120/1/ 1520 4 /1/ 2 ParentId基本上都是重复的,因为它们都指向父对象。将来,NodeId将会被ParentId取代。

但是,与此同时,我需要确保它们保持同步,因此我需要写一个约束来确保这一点:

HierarchyId

如何将其写为约束?

更新

我按照建议尝试了Damiens解决方案。它可以对现有数据强制执行多列完整性。但是,NodeId可以在层次结构中从左到右更改。例如,declare @id int = 4 DECLARE @result int = 0, @parentNodeId1 HierarchyId,@parentNodeId2 HierarchyId, @parentId int; Select @parentNodeId1 = NodeId.GetAncestor(1), @parentId = parentId from Items where id = @id; Select @parentNodeId2 = NodeId from Items where Id = @parentId; if @parentNodeId1 = @parentNodeId2 Select @result = 1; 的NodeId可以更改为/1/。它的父级未更改(父级为/3/),因此外键实际上尚未生效。这适用于没有孩子的物品。

但是,如果某项包含子项,并且NodeId已更改,则数据库引擎会将其视为违反外键并引发错误。

请参阅此数据库提琴:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=44637c2bbed80b8db3f305933798cdad

/

1 个答案:

答案 0 :(得分:2)

如果我们可以添加另一列,则外键约束可以强制执行此操作:

create table T(
    Id int not null,
    NodeId hierarchyid,
    ParentId int,
    _ParentNodeId as NodeId.GetAncestor(1) persisted,
    constraint PK_T primary key (Id,NodeId),
    constraint FK_T_Parent foreign key (ParentId,_ParentNodeId) references T (Id,NodeId)
)

(我将PK用作FK目标,但是如果Id是当前PK且您想保留它,则任何唯一约束都将起作用)

我为新列名加上了_。这是我的惯例,“我出于强制性而在我的中添加此列。我什至不希望其他人看到它”。