[英]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.