|
Posted on 2006-10-15 03:16 大大毛 阅读(882) 评论(0) 编辑 收藏 所属分类: SQL
树型结构在应用中被广泛的运用,在数据操作上需要一定的技巧来进行处理:
在表结构的定义上,有多种方式可以采用。 .数据表: a.单向链表式的结构 ( 这是藕给它起的名称,因为它与链表的结构相似,除了必要的自身描述外,就只包含父节点的位置) DDL示例:
--相当于单向链表 create table linkTree ( id varchar(10) primary key, --节点自身ID nodeContent varchar(50), --节点内容 parentId varchar(10) default '' --父节点ID ) 优点: .列宽固定,表结构易维护; .查找指定节点的上/下游节点效率高; .维护树型结构方便(增/删层); 缺点,如在下列情况中,都需要多次Select完成: .从指定节点开始列出全部子树 ( 除 Oracle 提供支持外 ); .返回从指定节点A到其子节点B的路径 ( B 与 A 的层数相差会大于 1 );
DML示例: 向下查找及统计子节点(仅一层) (1)通过父节点的ID
 通过父节点的ID --查找子节点 select * from linkTree where parentId = '01' --统计子节点数量 select parentId, count(*) 'count' from linkTree where parentId = '01' group by parentId (2)通过父节点的内容
 条件列nodeContent上存在唯一性约束 --查找子节点 select * from linkTree where parentId = (select id from linkTree where nodeContent = 'Root') --统计子节点数量 select parentId, count(*) 'count' from linkTree where parentId = (select id from linkTree where nodeContent = 'Root') group by parentId 由于条件列无唯一性约束,所以在查找时有可能会返回一个记录集,需要做一些处理:
 条件列nodeContent上无唯一性约束 --查找子节点,此处仅返回具有子节点的父节点行,如果需要返回全部则用right join select sub.id parentId, main.id, main.nodeContent from linkTree main join (select id from linkTree where nodeContent = 'depart1') sub on main.parentId = sub.id order by parentId --统计子节点数量,使用right join返回全部统计数 select parentId, count(id) 'count' from ( select sub.id parentId, main.id from linkTree main right join (select id from linkTree where nodeContent = 'depart1') sub on main.parentId = sub.id ) tree group by parentId (3)查找兄弟节点
 查找兄弟节点 --使用唯一列 select parentId, id brotherId, nodeContent from linkTree where parentId = (select parentId from linkTree where id='01') --使用非唯一列,由于一父多子的对应关系,因此需要注意使用distinct关键字 select sub.parentId, main.id brotherId, main.nodeContent from linkTree main join (select distinct parentId from linkTree where nodeContent = 'depart1') sub on main.parentId = sub.parentId order by parentId (4)遍历树 由于链表式表结构的特点,决定了无法用通用的单次 Select 完成操作,对于不同的 DBMS 可以采取不同的策略: 如Oracle select * from linkTree start with id='00' connect by PRIOR id = parentId; 如Ms-SQL2000 表的结构决定了数据只能逐层查找,网上常见的有使用存储过程进行递归返回表变量来实现。 这里我用循环的方式来实现,效率比递归+表变量要高。
 Ms-SQL2000遍历树
--这里定义的两个参数
declare
@level int, --查找层次
@start varchar(2); --开始节点ID
select @level = 3,@start = '00'; --示例赋参
--临时变量
declare @flag int; --当前处理节点的层次
declare
@t table (
id varchar(2),
nodeContent varchar(20),
parentId varchar(2),
site varchar(200),
flag int
);
--初始化
set @flag = 1;
insert into @t
select
linkTree.*,
linkTree.id,
@flag
from
linkTree
where
id = @start
--循环查找,结束条件(1.达到指定查找层次;2.没有任何匹配记录;)
while @@rowcount > 0 and @flag < @level
begin
set @flag = @flag + 1; --查找层次递增
--向下查找匹配子节点
insert into @t
select
linkTree.id,
linkTree.nodeContent,
linkTree.parentId,
t.site + linkTree.id,
@flag
from
@t t join linkTree on linkTree.parentId = t.id
where
t.flag = @flag - 1
end
--结果输出
select * from @t order by site 注:这里引入一个site列,是为了能够在输出时更加好的进行排序,因为在最终输出至网页时很有可能是顺序向下输出的,这里正好体现出这种结构。
b.位置描述式的结构 ( 这是藕给它起的名称,它有一个列,该列描述了当前节点在树中的位置) DDL示例:
create table siteTree ( id varchar(2) primary key, nodeContent varchar(20), site varchar(200) ) 例子: 01 Root 01 02 dep1 0102 03 dep2 0103 04 dep11 010201
优点: 由于该表结构中带一个位置描述列site,因此对于关于树的遍历等问题的解决将变得异常的轻松。位置列按从根结点到当前结点的ID连接而成。
缺点: 有利即有弊,位置描述列也同时突出该种结构的缺点,它最大的缺点就是树的层次不可能是无穷的,由于它由整个路径的ID连接而已,因此该列的宽度并不是固定的,如根节点的长度将是ID列的宽度,而当前节点位置列所需要空间 = 当前节点层次 * ID列宽度。 针对链表式结构的优点,这里就成了缺点,层次间的增删将变得较为困难。
遍历树:
--输出指定节点的全部子节点 select * from siteTree where CHARINDEX('00',site)=1 order by site
|