7

私はこれでかなりの時間を過ごしています。再帰関係 (階層) を持つテーブルに対して (Oracle を使用して) クエリを作成し、ツリー内の各ノードの下にある別のテーブルに格納されているレコードの総数を取得しようとしています。もう一方のテーブルには、リーフ ノードに関連付けられたレコードのみが含まれます。ただし、ツリーの各ノードとその下の合計を取得したいと考えています。たとえば、2 つのテーブルがあるとします。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

上記に一致するサンプル データを使用してテーブルを作成するための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;
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 に答える