Q:以最简单的表结构设计出符合需求的组织
架构?
A:组织架构通常是树形结构,上级包含下级所有权限。因此表结构可以如下设计:
+----+------+--------+
| ID | NAME | parent |
+----+------+--------+
其中parent为
外键列,引用指向当前表ID,同时约束CHECK(ID <> parent) 来确保数据的有效性。
Q:是否可以仅通过一条SQL获取指定ID的所有子集列表?
A:不能。一条SQL只能在数据库执行一次,SQL仅具备常规逻辑(与[and], 或[or, in, not in], 非[is null, is not null])能力不具备如
循环、
递归等能力,所以不能直接通过一条SQL语句获取到所有需要的数据;因此要获取子集列表只能通过程序控制;
Q:如何获取子集列表?
A:可以有两种选择:
1、使用数据库支持的存储过程(Procedure);
2、使用
编程语言(如:Java,C#,PHP等,该文以Java为例)循环实现;
对比:
+----+--------+----------------+
| | Procedure | PL(Programming Languages) |
+----+--------+----------------+
| 优点 | 减少SQL传输 | 语言性能更强,更容易控制 |
+----+--------+----------------+
| 缺点 | 增加DB响应时间 | 层次深、节点多时,SQL发 |
| | | 送次数不确定 |
+----+--------+----------------+
递归层次3层以下且分支在2条左右可以使用PL实现,在此作者推荐Procedure方式实现;
Q:如何避免在树架构中出现图架构(回环)?
A: 关于这个问题,作者和同事在初时也是头疼不已;如何规避树结构夹杂图结构主要由以下两方面入手:
第一、数据插入前,递归(循环) 验证目标节点(TN--Target Node)未出现在准父级( FTB--Father-To-Be)的父节点列表中;从 TN->FTB 是不好查询的,而反过来则要容易得多:FBT->TN;
第二、为防止DB(数据库) 被通过非法途径污染架构树,在获取子集时也需要做验证(FBT->TN);
*第三、设置插入
触发器(IT--Insert Trigger),更新触发器(UT--Update Trigger),在触发器中验证 FBT->TN合法性;
第四、经
研究讨论后,
发现一种更有效的方式避免在树结构中出现图结构:
为树结构中的每个节点定义层级概念!
+----+------+--------+-------+
| ID | NAME | parent | Level |
+----+------+--------+-------+
| 1 | name1| null | null |
+----+------+--------+-------+
| 2 | name2| 1 | 2 |
+----+------+--------+-------+
| 3 | name3| 1 | 2 |
+----+------+--------+-------+
| 4 | name4| null | null |
+----+------+--------+-------+
| 5 | name5| 3 | 3 |
+----+------+--------+-------+
需求:1、将ID(3)父节点修改为ID(2). a:获取ID(2)层级值(L2)
b:获取ID(3)层级值(L3)
c:验证ID(3)与ID(2)层级关系,被移动节点不能高于目标节点(L3>L2)
d:获取L3需被提升的层次:DV=L3-L2-1 (DV--Difference Value)
e:修改以ID(3)为根的所有子节点(包括ID(3))层次都提升
2、将ID(4)父节点分配为ID(3).
a:获取ID(3) 层级值(L3)
b:将L4修改为L3+1后完成操作
3、将ID(5)父节点修改为ID(4).
a:获取ID(4)层级值L4
b:获取ID(5)层级值L5
c:ID(5)不是根节点(L5<>1),设置L4=L5-1
d:ID(5)是根节点,设置L4=1同时修改以ID(5)为根的所有子节点(包括ID(5))层次都降低1