在实际应用中, 树结构数据的应用是很广泛的, 如书的目录结构, 组织部门的分级等!!!!!
如一本书的目录
name | code | P_code |
目录 | MULU | 0 |
第一章 | zh_1 | MULU |
第一节 | ji_1_1 | zh_1 |
第一回 | hu_1_1_1 | ji_1_1 |
第二回 | hu_1_1_2 | ji_1_1 |
第三回 | hu_1_1_3 | ji_1_1 |
第二节 | ji_1_2 | zh_1 |
第一回 | hu_1_2_1 | ji_1_2 |
第二回 | hu_1_2_2 | ji_1_2 |
第三回 | hu_1_2_3 | ji_1_2 |
第二章 | zh_2 | MULU |
…….. |
如果我们想要一次统计一些东西, 但是要分 目录, 章,节,回 ! 相关的东西只和回有直接的关系!
那我们的数据就必须是这样的
A 对应 第一章第二节第三回, 转换为: A 第一章, 第二章第二节, 第一章第二节第三回 这样就行了!!!
oracle 有专门的方法展现树数据, 这个相对其他类型的数据库方便很多!!!
select tt.code, tt.name,tt.p_code,
code_path,name_path,
regexp_substr(code_path,'[^/]+[A-Za-z0-9_]*',1,1) lev1_code,
regexp_substr(name_path,'[^/]+[A-Za-z0-9_]*',1,1) lev1_name,
regexp_substr(code_path,'[^/]+[A-Za-z0-9_]*',1,2) lev2_code,
regexp_substr(name_path,'[^/]+[A-Za-z0-9_]*',1,2) lev2_name,
regexp_substr(code_path,'[^/]+[A-Za-z0-9_]*',1,3) lev3_code,
regexp_substr(name_path,'[^/]+[A-Za-z0-9_]*',1,3) lev3_name
from (
select t.*,level,CONNECT_BY_ROOT code as root,CONNECT_BY_ISLEAF ,
SYS_CONNECT_BY_PATH (code, '/') code_path,
SYS_CONNECT_BY_PATH (name, '/') name_path
from book_mulu t
START WITH p_code='0'
CONNECT BY NOCYCLE t.p_code = PRIOR t.code) tt
我这里是用到了oracle 的connect by 这个语法, 网上很多资料的.
要从树的上面往下查, 还是树的下面往上查呢, 这个关键字 Prior(优先的) 的位置就是关键了!!! 男士女士, 女士优先, 那么男士 女士prior, 女士占有prior. 所以, 从树的上面往下查, 下面的优先, 所以prior 给code; 树的下面往上查, 上面的优先, prior 给p_code, 这样就很容易理解了!!! NOCYCLE 是针对环状循环的问题数据的!!!
level, connect_by_root, connect_by_isleaf, CONNECT_BY_ISCYCLE 这四个是connect by 语法中特有的关键字, 可能还有其他的, 我暂时不清楚!!!
level 是树的级数, 从1开始!(这里的树指查询出来的数据树,该数据树可能是整棵树的一部分而已);
connect_by_root 是树的首节点;
connect_by_isleaf 是指当前节点是否为叶子, 1 是; 0 否;
CONNECT_BY_ISCYCLE 如果在当前行中引用了某个父亲节点的内容并在树中出现了循环, 会显示“1”; 否则就显示“0”;
sys_connect_by_path 函数, 可能在一些行列转换的处理中,大家就使用过了, 很好的一个函数, 能把树的目录层次串联起来!!!!
如 SYS_CONNECT_BY_PATH (name, '/') 结果就是: 第一章/第二节/第三回.
有了这些, 我们再对数据进行整合, 在有明确层次树的情况下, 再结合一些oracle 的字符串函数, 就很方便地把层次分列了!