【问题标题】:Getting counts at each level of a hierarchical query在分层查询的每个级别获取计数
【发布时间】:2016-01-26 23:18:14
【问题描述】:

参考之前的问题答案之一, Getting counts/totals at each level of a hierarchical query using CONNECT BY

DIRS
====
DIR_ID 
PARENT_DIR_ID
DIR_NAME

FILES
=====
FILE_ID
FILE_NAME
DIR_ID
FILE_SIZE


       If DIRS contains:

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

Out Out is shown below.



 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    File_Size
=====                   ===========   --------
/ROOT                   6               1050
/ROOT/DIR1_1            4               450 
/ROOT/DIR1_1/DIR2_1     1               100 
/ROOT/DIR1_1/DIR2_2     3               350  
/ROOT/DIR1_2            2               600

  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 

我怎样才能获得大小列旁边的文件大小列的计数。

除了文件大小的总和之外,这个查询做得很好。

           (select count(file_id)                       
               from dirs dc                              
                    ,files f                             
              where f.dir_id(+) = dc.dir_id              
            connect by prior dc.dir_id = dc.parent_dir_id
              start with dc.dir_id = dp.dir_id           
            ) count, 
            (select sum(file_size)                       
                       from dirs dc                              
                            ,files f                             
                      where f.dir_id(+) = dc.dir_id              
                    connect by prior dc.dir_id = dc.parent_dir_id
                      start with dc.dir_id = dp.dir_id           
            ) size   
      from dirs dp                                       
     connect by prior dp.dir_id = dp.parent_dir_id      
start with dp.parent_dir_id is null

我修改了查询以获取每个级别的文件大小,但没有成功。知道缺少什么吗?

我需要的只是 File_Size 列的计数,如上所示。

【问题讨论】:

    标签: sql oracle hierarchical-data recursive-query connect-by


    【解决方案1】:

    我想出了多种解决方案,不妨在这里一一列举。

    子查询方法

    这就是您使用的 - 列出每个目录,为每个目录执行两个递归子查询。我基本上重复了你在这里写的内容,它按预期工作。您的错误是使用保留字 count 和 size 作为列名。

    select sys_connect_by_path(dp.dir_name, '/') path,
    (select count(file_id)
       from dirs dc, files f
      where f.dir_id(+) = dc.dir_id
    connect by prior dc.dir_id = dc.parent_dir_id
      start with dc.dir_id = dp.dir_id
      ) cnt,
    (select sum(file_size)
       from dirs dc, files f
      where f.dir_id(+) = dc.dir_id
    connect by prior dc.dir_id = dc.parent_dir_id
      start with dc.dir_id = dp.dir_id
      ) sz
    from dirs dp
    connect by prior dp.dir_id = dp.parent_dir_id
    start with dp.parent_dir_id is null;
    

    但是,在较大的数据集上,这可能会很慢。还有其他方法。

    简单的加入方法

    这个效率不是很高并且有一些限制,但似乎很容易理解。对我来说,它的执行速度比子查询快一点。

    1) 获取完整的目录层次结构

    2) 针对 (1) 加入文件以找出每个文件的完整目录名

    3) 在file_dirname like dirname||'%' 上加入(1) 和(2) 以获取属于指定目录或其任何子目录的文件列表,然后group by (1).dir_id 并获得总和。

    请注意,目录名必须全部以“/”结尾才能正常工作;此外,目录完整路径必须是唯一的。

    它看起来像这样:

    with dirs_r as
    (select sys_connect_by_path(dp.dir_name, '/')||'/' path, dir_id
      from dirs dp                                       
    connect by prior dp.dir_id = dp.parent_dir_id      
      start with dp.parent_dir_id is null
    )
    
    select dirs_r.path, count(*), sum(files_q.file_size)
      from dirs_r,
      (select d.path, f.file_size
        from files f, dirs_r d
       where d.dir_id = f.dir_id) files_q
     where files_q.path like dirs_r.path||'%'
    group by dirs_r.path
    order by dirs_r.path
    

    反向方法:

    这可能有点难以理解,但按照解释计划效率更高,而且它也只使用 ID,因此更可靠。它的执行速度也比上述两者都快。

    1) 使用dp.dir_id = prior dp.parent_dir_id 和connect_by_root(dir_id) 为每个目录构建一个reverse 目录层次结构。这样,您可以获得每个目录 ID 及其所有父目录的行。

    2) 与文件连接 (1),获取每个文件的每个父目录的行。

    3) 加入 (2) 与 dir_id 上的直接层次结构,然后分组。

    select dirs_r.path, count(*), sum(filedir.file_size) from
    (select sys_connect_by_path(dp.dir_name, '/') path, dir_id
      from dirs dp                                       
    connect by prior dp.dir_id = dp.parent_dir_id      
      start with dp.parent_dir_id is null
    ) dirs_r,
    
    (select f.file_size, dirs_reverse.dir_id dir_id
      from files f,
           (select connect_by_root(dp.dir_id) inner_dir_id, dp.dir_id
              from dirs dp
           connect by dp.dir_id = prior dp.parent_dir_id  
           ) dirs_reverse
     where dirs_reverse.inner_dir_id = f.dir_id) filedir
    
    where dirs_r.dir_id = filedir.dir_id
    group by dirs_r.path
    order by dirs_r.path
    

    【讨论】:

      猜你喜欢
      • 2014-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多