2013-02-20 136 views
2

我们的数据库中有一个使用hierarchyid数据类型的表,我试图找到一种方法来重新分配父项所有的子项给新的父项。我已经找到方法来移动孩子,但父母不会被重新分配。我的表看起来像这样:在SQL层次结构数据中移动父项和子项

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仍然是一个孩子移动家长和孩子的位置4,而不是3 ...这是我不想要的。

任何帮助表示赞赏!

回答

0

重复的错误很可能是由于您将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; 
0

我知道这是一个迟到的反应,但我解决了类似的问题是要移动基于祖父相当比直接的父母。

在我的例子中,我有一个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 
相关问题