闭包表的增删改查(达梦数据库)

闭包表的增删改查(达梦数据库)

在开发中我们最常使用邻接表,像有上下级关系的数据经常会把父节点和子节点存在同一行,如果要找某个节点下所有的子节点,就必须重复递归去寻找,而且我们并不知道树的深度,随着树深度的加深,性能也会越受影响。

最近梳理闭包表,由于 修改 操作费了点时间,所以做个笔记备忘一下。
(如果哪里有误,还请提醒一下。)

介绍

闭包表是用两张表来存储数据,利用空间换时间。一张表只保存节点的信息,另外一张表保存节点之间的路径即父节点与子节点之间的距离(深度)。

表结构

CREATE TABLE "NODE"
(
"ID" VARCHAR(96) NOT NULL,
"PARENT_ID" VARCHAR(96),
"NODE_NAME" VARCHAR(300) NOT NULL,
CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ;
COMMENT ON TABLE "NODE" IS '节点表';
COMMENT ON COLUMN "NODE"."ID" IS '主键';
COMMENT ON COLUMN "NODE"."PARENT_ID" IS '父节点(也可不存,通过path表中的distance查找)';
COMMENT ON COLUMN "NODE"."NODE_NAME" IS '节点名称';
;
 CREATE TABLE "PATH"
(
"ID" BIGINT IDENTITY(1, 1) NOT NULL,
"ANCESTOR_ID" VARCHAR(50) NOT NULL,
"DESCENDANT_ID" VARCHAR(50) NOT NULL,
"DISTANCE" BIGINT NOT NULL,
CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ;
COMMENT ON TABLE "PATH" IS '路径表';
COMMENT ON COLUMN "PATH"."ANCESTOR_ID" IS '祖先节点';
COMMENT ON COLUMN "PATH"."DESCENDANT_ID" IS '后代节点';
COMMENT ON COLUMN "PATH"."DISTANCE" IS '祖先节点与后代节点的距离(深度)';
COMMENT ON COLUMN "PATH"."ID" IS '主键';

数据存储

树结构

  1. 节点表(node)
    在这里插入图片描述

  2. 路径表(path)
    为了方便与图对应,路径表中的ID先用A、B、C等表示 在这里插入图片描述

查找

查找B的祖先节点

select ancestor_id from path where descendant_id = #{B_ID} and ancestor_id != descendant_id order by distance desc

查找B的后代节点

select descendant_id from path where ancestor_id = #{B_ID} and ancestor_id != descendant_id order by distance

增加(增加F节点为C节点的子节点)

增加节点

  1. 首先在“节点表”里添加新节点
 insert into node (parent_id, node_name) values ('C_ID','F_ID')
  1. 在“路径表”中添加路径关系
    (1) 先添加新节点与自己间的路径
insert into path(ancestor_id, descendant_id,distance) values ('F_ID','F_ID',0)

(2) 再添加新节点与所有祖先节点之间的路径(JAVA)

//查询新节点父节点的祖先节点(包含父节点自己,也就是节点C A)
select * from path where descendant_id = #{C_ID} order by distance desc
//queryAncestor(新节点父节点的祖先节点,包含父节点自己)
 List<Path> ancestorNodes = PathService.queryAncestor(node.getParentId());
 //再添加新节点与所有祖先节点之间的路径
 if (ancestorNodes != null) {
    List<Path> paths = new ArrayList<>();
    for (Path pathA : ancestorNodes) {
         Path pathN = new Path();
         pathN.setAncestorId(pathA.getAncestorId());
         pathN.setDescendantId(node.getId());
         if (pathA.getDistance() != null) {
             pathN.setDistance(pathA.getDistance() + 1);
         }
         paths.add(pathN);
    }
    PathService.saveBatch(paths);
 }

增加节点

修改(把B节点移到C节点下)

移动节点

  1. 首先解除B的所有祖先节点(节点A)与B及其所有后代节点(节点D、E)之间的路径
delete from path where
descendant_id in (select descendant_id from path where ancestor_id = #{B_ID})
and
ancestor_id in (select ancestor_id from path where descendant_id = #{B_ID} and ancestor_id != descendant_id)

解除关系
2. 建立新路径,即B节点的新父节点及其所有祖先节点(节点C和节点A) 与 B节点及其所有后代节点(节点D、E) 间的路径(笛卡尔积)

select p.ancestor_id ancestor_id, s.descendant_id descendant_id, p.distance + s.distance + 1 distance
from path p
cross join path s
where p.descendant_id = #{C_ID} and s.ancestor_id = #{B_ID}

建立新关系

删除(删除节点B)

删除节点

  1. 删除“节点表”中的B节点及B节点所有后代节点(D、E)信息
delete from node where id in (select descendant_id from path where ancestor_id = #{B_ID} and del_flag = '0')
  1. 删除“路径表”中节点所有后代节点(包括自己)(节点B、D、E)与祖先节点(节点A)之间的路径
delete from path where
descendant_id in (select descendant_id from path where ancestor_id = #{B_ID})

删除节点

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值