2012-09-10 57 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