[英]How to write multi-line constraint for ParentId/HierarchyId
我有一个名为Items的表,具有以下三个字段:
节点编号(HierarchyId)
Id NodeId ParentId 2 / NULL 3 /120/1/ 1520 4 /1/ 2
ParentId
和NodeId
基本上都是重复的,因为它们都指向父对象。 将来, ParentId
将被ParentId
为HierarchyId
。
但是,与此同时,我需要确保它们保持同步,因此我需要编写一个约束来确保这一点:
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;
如何写为约束?
更新
我按照建议尝试了Damiens解决方案。 它可以对现有数据强制执行多列完整性。 但是,NodeId可以在层次结构中从左到右更改。 例如, /1/
的NodeId可以更改为/3/
。 它的父级没有更改(父级是/
),因此实际上外键尚未经过验证。 这适用于没有孩子的物品。
但是,如果项目具有子项,并且NodeId已更改,则数据库引擎会将其视为违反外键,并引发错误。
看到此数据库提琴: https ://dbfiddle.uk/ ? rdbms = sqlserver_2017 & fiddle = 44637c2bbed80b8db3f305933798cdad
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[People](
[Id] [int] NOT NULL,
[ParentId] [int] NULL,
[NodeId] [hierarchyid] NOT NULL,
[_ParentNodeId] AS ([NodeId].[GetAncestor]((1))) PERSISTED,
CONSTRAINT [PK_People] PRIMARY KEY CLUSTERED
(
[Id] ASC,
[NodeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT [dbo].[People] ([Id], [ParentId], [NodeId]) VALUES (1, NULL, N'/')
GO
INSERT [dbo].[People] ([Id], [ParentId], [NodeId]) VALUES (2, 1, N'/2/')
GO
INSERT [dbo].[People] ([Id], [ParentId], [NodeId]) VALUES (3, 1, N'/3/')
GO
INSERT [dbo].[People] ([Id], [ParentId], [NodeId]) VALUES (4, 2, N'/2/1/')
GO
INSERT [dbo].[People] ([Id], [ParentId], [NodeId]) VALUES (5, 4, N'/2/1/1.1/')
GO
ALTER TABLE [dbo].[People] WITH CHECK ADD CONSTRAINT [FK_People_Parent] FOREIGN KEY([ParentId], [_ParentNodeId])
REFERENCES [dbo].[People] ([Id], [NodeId])
GO
ALTER TABLE [dbo].[People] CHECK CONSTRAINT [FK_People_Parent]
GO
Update People set NodeId = N'/2/1/2/' where Id = 5--Works
Update People set NodeId = N'/2/2/' where Id = 4 --Error
如果我们可以添加另一列,则外键约束可以强制执行此操作:
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,而您想保留该唯一约束,则可以使用任何唯一约束)
我在新列名称前添加了_
。 这是我的约定,“ 我出于增强完整性的目的而添加此列。我不希望其他人看到它”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.