7

我玩得很开心。我正在尝试针对具有递归关系(分层)的表编写查询(使用 Oracle),并获取存储在树中每个节点及其下方的另一个表中的记录总数。另一个表只有与叶节点关联的记录。但是,我想获得树中每个节点及其下方的总数。例如,假设我有两张桌子。DIRS 包含目录名称和标识目录结构的递归关系,而 FILES 包含文件信息,其中 DIRS 的外键指示文件所在的目录:

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

更新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;
4

2 回答 2

4

这个很简单:

09:38:54 HR@vm_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 HR@vm_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                                      
于 2012-09-11T01:39:53.683 回答
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

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

于 2012-09-10T23:53:20.433 回答