2012-09-10 31 views
6

获取分层查询的每个级别的计数/总计我有这样的时间。我正在尝试使用递归关系(分层)编写查询(使用Oracle),并获取存储在树中每个节点上下的另一个表中的记录总数。另一个表只有与叶节点相关的记录。但是,我想获得树中每个节点上下的总数。例如,假设我有两张桌子。 DIRS包含目录名称和递归关系鉴别的目录结构,文件和文件包含一个外键DIRS指示文件所在的目录文件信息:使用CONNECT BY

DIRS 
==== 
DIR_ID 
PARENT_DIR_ID 
DIR_NAME 

FILES 
===== 
FILE_ID 
FILE_NAME 
DIR_ID 
FILE_SIZE 

如果DIRS包含:

DIR_ID PARENT_DIR_ID DIR_NAME 
====== ============= ======== 
1      ROOT 
2  1    DIR1_1 
3  1    DIR1_2 
4  2    DIR2_1 
5  2    DIR2_2 

和FILES包含

FILE_ID FILE_NAME DIR_ID FILE_SIZE 
======= ========= ====== ========= 
1   test1.txt 5  100 
2   test2.txt 5  200 
3   test5.txt 5   50 
4   test3.txt 3  300 
5   test4.txt 3  300 
6   test6.txt 4  100 

我想,在票数与文件的数目以及返回或下面的每个节点的路径查询君主国。基本上是文件数量的汇总。所以查询结果将类似于:

Path     File_Count 
=====     =========== 
/ROOT     6 
/ROOT/DIR1_1   4 
/ROOT/DIR1_1/DIR2_1  1 
/ROOT/DIR1_1/DIR2_2  3 
/ROOT/DIR1_2   2 

UPDATE SQL脚本来创建示例数据表,以匹配上面:

create table DIRS (dir_id number(38) primary key 
    , parent_dir_id number(38) null references DIRS(dir_id) 
    , dir_name varchar2(128) not null); 

create table FILES (file_id number(38) primary key 
    , file_name varchar2(128) not null 
    , dir_id number(38) not null references DIRS(dir_id) 
    , file_size number not null 
    , unique (dir_id, file_name)); 

insert into DIRS 
select 1, null, 'ROOT' from dual 
union all select 2, 1, 'DIR1_1' from dual 
union all select 3, 1, 'DIR1_2' from dual 
union all select 4, 2, 'DIR2_1' from dual 
union all select 5, 2, 'DIR2_2' from dual; 

insert into files 
select 1, 'test1.txt', 5, 100 from dual 
union all select 2, 'test2.txt', 5, 200 from dual 
union all select 3, 'test5.txt', 5, 50 from dual 
union all select 4, 'test3.txt', 3, 300 from dual 
union all select 5, 'test4.txt', 3, 300 from dual 
union all select 6, 'test6.txt', 4, 100 from dual; 

commit; 
+0

哪个Oracle的版本? 11g R2添加了递归子查询因子分解,这可能比'connect by'提供更清晰的解决方案。 –

+0

是11g R2。将研究“子查询因子”。不熟悉这一点。 – GregH

+0

看起来像在Oracle 9.2中添加了子查询因子 – GregH

回答

1
select sys_connect_by_path(D.dir_name, '/'), S.count_distinct_file_id 
from DIRS D 
inner join (select subtree_root_dir_id 
      , count(distinct file_id) count_distinct_file_id 
     from (select distinct connect_by_root D.DIR_ID subtree_root_dir_id 
        , F.file_id 
       from DIRS D 
       left outer join FILES F on F.dir_id = D.dir_id 
       start with 1=1 connect by prior D.dir_id = D.parent_dir_id) 
     group by subtree_root_dir_id) S 
    on D.dir_id = S.subtree_root_dir_id 
start with D.dir_id = 1 connect by prior D.dir_id = D.parent_dir_id 

给出你要的结果,但我的直觉说我没有看到任何东西,而且查询可以更简单。 (请不要接受这个答案直到几天过去了,在希望有人提出一个更好的答案。)

4

这一个是非常简单的:

09:38:54 [email protected]_xe> l          
    1 select sys_connect_by_path(dp.dir_name, '/') path  
    2   ,(select count(file_id)      
    3    from dirs dc        
    4     ,files f        
    5   where f.dir_id(+) = dc.dir_id    
    6   connect by prior dc.dir_id = dc.parent_dir_id 
    7   start with dc.dir_id = dp.dir_id   
    8   ) count          
    9 from dirs dp          
10 connect by prior dp.dir_id = dp.parent_dir_id  
11* start with dp.parent_dir_id is null     
09:38:55 [email protected]_xe>/          

PATH        COUNT     
------------------------------ ----------     
/ROOT         6     
/ROOT/DIR1_1       4     
/ROOT/DIR1_1/DIR2_1      1     
/ROOT/DIR1_1/DIR2_2      3     
/ROOT/DIR1_2       2     

5 rows selected.           

Elapsed: 00:00:00.02