批量移动树结点

1.    问题描述

树形结构用途广泛,不可避免地要用到树结点的移动,如果按照数据库规范来设计的话,对于批量移动结点时, 对所移动结点的子孙结点是没有影响的,因为子结点只要有它的父结点的ID就可以了,但是如果要查询某结点的所有子孙结点时,这种设计在性能上就很难满足,通常要用递归才能完成。为了方便查询,在表结构中多添加一个字段Tree_AncestorsId ,用于存放祖先结点,这样, 查询某结点E的所有子孙结点时,只要在查找 Tree_AncestorsId 中存在 /E/ 内容的结点,就是所要查找的结点.此设计方便了查询,但给结点的移动带来麻烦:移动一个结点时,此结点下所在子结点的Tree_AncestorsId 都要修改.一般的做法是用递归的方法更新所有子点的Tree_AncestorsId 字段,这样更新一个节点的代价很高, 经过摸索,有简单的方法可以达到要求,就是下面要描述的内容。

 

2.    结点E移动前后结构如下所示


3.    数据库存储结构如下表所示:

 

列名

类型

备注

Tree_Id

Int (4)

主键

Tree_Name

Nvarchar(20)

结点名

Tree_ParentId

Int

父结点Id

Tree_AncestorsId

Varchar(4000)

祖先结点Id,包括父结点

...

 

 

表1

4.    解决方法:

移动E结点到F结点下时:

1).E结点的Tree_ParentId和Tree_AncestorsId 要修改。

2).E结点的所有子孙结点(G,H,I,J)的Tree_ParentId 不变,但 Tree_AncestorsId都要修改。

3).G,H,I,J 的 Tree_AncestorsId 修改时,可以将字段中 /A/B/E/.. 修改成/A/B/D/F/E/..,因为 /E/后面的内容不用修改,看下表所示.

 

4).移动前结点字段数据

Tree_Id

Tree_ParentId

Tree_AncestorsId

...

 

 

B

A

/A/

E

B

/A/B/

G

E

/A/B/E/

H

E

/A/B/E/

I

H

/A/B/E/H/

J

I

/A/B/E/H/I/

表2

5).移动后结点字段数据

Tree_Id

Tree_ParentId

Tree_AncestorsId

...

 

 

B

A

/A/

E

F

/A/B/D/F/

G

E

/A/B/D/F/E/

H

E

/A/B/D/F/E/

I

H

/A/B/D/F/E/H/

J

I

/A/B/D/F/E/H/I/

表3

6).对比表2和表3,红色字体表示结点移动后,内容发生了改变,蓝色字体表示结点移动后内容没有变化,因此, 移动E结点到F结点下时,将E结点的Tree_ParentId修改为F ,将Tree_AncestorsId修改为 /A/B/D/F/, E结点的子孙结点(G,H,I,J)只须修改Tree_AncestorsId 字段,对应的SQL语句如下:

 

--=============================================

-- Author:    yufei

-- Createdate: 2010-01-05

--Description:   批量移动树结点

--=============================================

CREATE PROCEDURE [dbo].[SP_Tree_Move]

@Tree_Id int,

@Tree_ParentId int

AS

BEGIN

    /*存放所移动结点的父结点的Tree_AncestorsId*/

    declare @AncestorsId nvarchar(4000)

 

    /*@AncestorsId赋值*/

    select @AncestorsId=Tree_AncestorsId fromDDPMDemo_T_Sales_Tree where Tree_Id=@Tree_ParentId

 

    /*修改第一个结点*/

    Update DDPMDemo_T_Sales_Tree set Tree_ParentId=@Tree_ParentId,

    Tree_AncestorsId=@AncestorsId+convert(varchar,@Tree_ParentId)+'/'

    where Tree_Id=@Tree_Id

 

    /*声明存放所移动结点E 移动后的祖先Tree_AncestorsId*/

    DECLARE @ANSTRING VARCHAR(500)

    /*声明要查询的内容,形如'%/E/%'  */

    DECLARE @REGSTR VARCHAR(500)

    /*@REGSTR赋值,形如'%/E/%'  */

    SET @REGSTR='%/'+convert(varchar,@Tree_Id)+'/%'

    /*@ANSTRING赋值*/

    SET @ANSTRING=@AncestorsId+convert(varchar,@Tree_ParentId)+'/'

 

    /*更新所移动结点E 的所有子孙结点的Tree_AncestorsId*/

    Update DDPMDemo_T_Sales_Tree

    set Tree_AncestorsId=@ANSTRING+SUBSTRING(Tree_AncestorsId,PATINDEX(@REGSTR,Tree_AncestorsId)+1,LEN(Tree_AncestorsId))

    WHERE PATINDEX(@REGSTR,Tree_AncestorsId)>0

END


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值