2

我正在将数据从一个数据库导入到另一个数据库。该hierarchyid列还必须在关系完好无损的情况下进行移植。

如果目标表是空的,这很容易。当目标包含行时,源表中的层次结构在目标表中将无效

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

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

我已阅读SQL Server 中的更新“Hierarchyid”,但看不到它如何应用于我的问题。

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

4

1 回答 1

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)) 的行。

要查看我们如何获取新 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

结果:

结果

于 2011-09-24T12:55:04.183 回答