【问题标题】:Move parent AND children in SQL Hierarchy data在 SQL 层次结构数据中移动父级和子级
【发布时间】:2013-02-20 14:57:39
【问题描述】:

我们的数据库中有一个使用 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 下,但 Locations 5、6 和 7 仍然是Location4 的孩子,而不是 3...这是我不想要的。

感谢任何帮助!

【问题讨论】:

    标签: sql-server sql-server-2008 hierarchical-data


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我知道这是迟到的回应,但我对类似问题的解决方案是根据祖父母而不是直接父母搬家。

      在我的示例中,我有一个填充 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-29
        • 2015-07-28
        • 1970-01-01
        • 1970-01-01
        • 2012-03-01
        • 1970-01-01
        相关资源
        最近更新 更多