更新SQL Server 2008中的所有HierarchyID节点

时间:2011-09-15 10:02:04

标签: sql-server-2008 hierarchyid

我正在将数据从一个数据库导入另一个数据库。还必须移植hierarchyid列,关系完好无损。

如果目标表为空,则很容易。当目标包含行时,源表中的层次结构在目标表

中无效

最简单的方法是使用第一个移植行的主键的值递增层次结构字段中的所有值。

因此,如果源行的hierarchyid'/1/12/13/'且导入前目标中的下一个可用ID为101,则层次结构应更改,以使每个值增加100:'/101/112/113/'

我已阅读Updating “Hierarchyid” in SQL Server,但看不出它如何应用于我的问题。

如何将每行的每个hierarchyid中的每个数字递增1个设置值,即将层次结构字段中的所有数字递增100?

1 个答案:

答案 0 :(得分:3)

看看这个解决方案(解释可以在下面找到):

DECLARE @Source TABLE
(
    ID HIERARCHYID PRIMARY KEY
    ,Name NVARCHAR(50) NOT NULL
);

DECLARE @Target TABLE
(
    ID HIERARCHYID PRIMARY KEY
    ,Name NVARCHAR(50) NOT NULL
    ,OldID HIERARCHYID
);

INSERT  @Source 
VALUES  
        ('/1/','a'), ('/1/1/','aa'), ('/1/2/','ab'), ('/1/3/','ac')
        ,('/2/','b')
        ,('/3/','c'), ('/3/3/','cc')
        ,('/4/','d'), ('/4/1/','da'), ('/4/2/','db'), ('/4/2/1/','dba'), ('/4/2/1/5/','dbaf');

DECLARE @LastTargetRootNodeAsInteger INT;       
SELECT  @LastTargetRootNodeAsInteger = REPLACE( MAX( a.ID.GetAncestor( a.ID.GetLevel()-1 ) ).ToString(), '/', '')
FROM    @Target a;

WITH CteUpdate
AS
(
SELECT  a.ID 
        ,a.Name
        ,a.ID.GetAncestor( a.ID.GetLevel()-1 ) AS OldRootID
        ,CONVERT(HIERARCHYID,'/'+CONVERT(VARCHAR(256),@LastTargetRootNodeAsInteger+DENSE_RANK()OVER(ORDER BY a.ID.GetAncestor( a.ID.GetLevel()-1 )))+'/') NewRootID
FROM    @Source a
)
INSERT  @Target(ID, Name, OldID)
SELECT  a.ID.GetReparentedValue(a.OldRootID, a.NewRootID), a.Name, a.ID
FROM    CteUpdate a;

SELECT  *
        ,t.ID.ToString() AS CurrentNodeToString
        ,t.OldID.ToString() AS OldNodeToString
FROM    @Target t
ORDER BY t.ID;

说明:

  1. 第一步假设从目标表中找到最后一个根节点(@LastTargetRootNodeAsInteger)。
  2. 然后,对于源表中的每个ID,我们得到根节点(旧根节点:a.ID.GetAncestor( a.ID.GetLevel()-1 ))。
  3. 对于每个旧的根节点,我们获得新的根节点('/'+...+@LastTargetRootNodeAsInteger+DENSE_RANK()OVER(ORDER BY old_root_node)+'/')。
  4. 最后,我们将使用新的根节点(a.ID.GetReparentedValue(old_root,new_root))插入行。
  5. 要了解我们如何获取新ID,您可以执行此查询:

    SELECT  *
            ,c.ID.GetReparentedValue(c.OldRootNode,c.NewRootNode).ToString() AS NewCurrentNode
    FROM
    (
            SELECT  *
                    ,'/'+CONVERT(VARCHAR(256),@LastTargetRootNodeAsInteger+DENSE_RANK() OVER(ORDER BY b.OldRootNode))+'/' AS NewRootNode
            FROM
            (
                    SELECT  *
                            ,a.ID.ToString() AS OldCurrentNode
                            ,a.ID.GetAncestor( a.ID.GetLevel()-1 ).ToString() AS OldRootNode
                    FROM    @Source a
            ) b
    ) c
    

    结果:

    results