我们的数据库中有一个使用hierarchyid数据类型的表,我试图找到一种方法将父项及其所有子项重新分配给新父项。我已经找到了移动孩子的方法,但父母没有被重新分配。我的表看起来像这样:
LocationOrg
[OrgNode] [hierarchyid] NOT NULL,
[OrgLevel] AS ([OrgNode].[GetLevel]()),
[LocationID] [int] NOT NULL,
[LocationName] [varchar](20) NOT NULL
还有一些数据:
LocationID | LocationName
__________ |_____________
1 | Headquaters
2 | Location1
3 | Location2
4 | Location3
5 | Location4
6 | Location5
7 | Location6
8 | Location7
现在它是设置(手动),因此Location1和Location4是总部的子项,Location2和Location3是Location1的子项,而Location5,Location6和Location7是Location2的子项:
--Headquaters
--Location1
--Location2
--Location3
--Location4
--Location5
--Location6
--Location7
我怎样才能写出一些可以重新分配父母及其子女的东西?例如,如果我想将Location4及其所有子项移动到Location3下:
--Headquaters
--Location1
--Location2
--Location3
--Location4
--Location5
--Location6
--Location7
请注意来自Location4的所有孩子如何成为Location3的孩子...我不想整体移动父/子结构,我需要将他们重新分配给新的父母。
这是我到目前为止所得到的,但同样,它只会移动孩子,而不是它的父母:
ALTER PROC [dbo].[ReorderLocationOrg]
@LocationID int,
@NewParentLocationID int
AS
BEGIN
DECLARE @OldParent hierarchyid,
@NewParent hierarchyid
SELECT @OldParent = OrgNode
FROM LocationOrg
WHERE LocationID = @LocationID;
SELECT @NewParent = OrgNode
FROM LocationOrg
WHERE LocationID = @NewParentLocationID;
DECLARE children_cursor CURSOR FOR
SELECT OrgNode
FROM LocationOrg
WHERE OrgNode.GetAncestor(1) = @OldParent;
DECLARE @ChildId hierarchyid;
OPEN children_cursor
FETCH NEXT FROM children_cursor INTO @ChildId;
WHILE @@FETCH_STATUS = 0
BEGIN
START:
DECLARE @NewId hierarchyid;
SELECT @NewId = @NewParent.GetDescendant(MAX(OrgNode), NULL)
FROM LocationOrg
WHERE OrgNode.GetAncestor(1) = @NewParent;
UPDATE LocationOrg
SET OrgNode = OrgNode.GetReparentedValue(@ChildId, @NewId)
WHERE OrgNode.IsDescendantOf(@ChildId) = 1;
IF @@error <> 0 GOTO START -- On error, retry
FETCH NEXT FROM children_cursor INTO @ChildId;
END
CLOSE children_cursor;
DEALLOCATE children_cursor;
--Move Parent to new node.
--UPDATE LocationOrg
--SET OrgNode = @OldParent.GetReparentedValue(@OldParent2, @NewParent)
--WHERE OrgNode = @OldParent
END
正如您所看到的(注释掉部分),我试图在光标之后移动父节点,但是它会抛出一个错误,指出无法插入重复的记录。
我查看了Moving Subtrees上的这个链接,但是该程序在保持其结构的同时移动了父母和孩子,所以在我的情况下,Location4将被移动到Location3下,但是位置5,6和7仍然是Location4的孩子,而不是3 ...这是我不想要的。
任何帮助表示赞赏!
重复错误很可能是由于您将oldParent节点移动到新父节点下已占用的位置。
试试这个来移动sp中的旧父节点(在光标之后)
--Get a new Hierarchical id for you record
DECLARE @NewOldParentId hierarchyid
SELECT @NewOldParentId = @NewParent.GetDescendant(MAX(OrgNode), NULL)
FROM LocationOrg
WHERE OrgNode.GetAncestor(1) = @NewParent;
--Give this new id to the oldParent
UPDATE LocationOrg
SET OrgNode = @NewOldParentId
WHERE LocationID = @LocationID;
我知道这是一个迟到的回应,但我对类似问题的解决方案是基于祖父母而不是直接父母。
在我的示例中,我有一个4个类别,填充4个下拉列表。我正在使用层次结构表来跟踪依赖项。
在我的更新where子句中我得到祖父母的后代并移动id也只有孩子的后代(我关心的元素)我包括最后的<> @parentId作为附加检查(在应用程序中需要) 。
DECLARE @childID hierarchyid = (select id from DataCategories where Category_ID = 1) --the node I care about
DECLARE @oldParentID hierarchyid = @childID.GetAncestor(1) --direct parent
DECLARE @oldGrandParentID hierarchyid = @childID.GetAncestor(2) --grandparent
DECLARE @newParentID hierarchyid = (select id from DataCategories where Category_ID = 2) -- target parent
UPDATE DataCategories
SET id = id.GetReparentedValue(@oldParentID, @newParentID)
WHERE id.IsDescendantOf(@oldGrandParentID) = 1 AND id.IsDescendantOf(@childID) = 1 AND id <> @oldParentID