7

テーブル間の外部キーに基づいて、テーブルの依存関係グラフを作成しようとしています。このグラフは、任意のテーブル名をルートとして開始する必要があります。テーブル名を指定して、 all_constraints ビューを使用してそれを参照するテーブルを検索し、次にそれらを参照するテーブルを検索することもできますが、これは非常に非効率的です。すべてのテーブルに対してこれを行う再帰クエリを作成しましたが、追加すると:

START WITH Table_Name=:tablename

ツリー全体は返されません。

4

2 に答える 2

9
    select parent, child, level from (
select parent_table.table_name parent, child_table.table_name child
 from user_tables      parent_table,
      user_constraints parent_constraint,
      user_constraints child_constraint,
      user_tables      child_table
where parent_table.table_name = parent_constraint.table_name
  and parent_constraint.constraint_type IN( 'P', 'U' )
  and child_constraint.r_constraint_name = parent_constraint.constraint_name
  and child_constraint.constraint_type   = 'R'
  and child_table.table_name = child_constraint.table_name
  and child_table.table_name != parent_table.table_name
)
start with parent = 'DEPT'
connect by prior child = parent

すべてが同じスキーマにあると仮定すると、機能するはずです(もちろん、テーブル名を置き換えてください)。スキーマ間の依存関係を処理する必要がある場合は、OWNER列とR_OWNER列にDBA_バージョンのデータディクショナリテーブルと条件を使用します。さらに考えてみると、これは自己参照制約(つまり、MGR列がEMPNO列を参照するEMPテーブルの制約)も考慮していないため、対処する必要がある場合は、そのケースを処理するようにコードを変更する必要があります。自己参照制約付き。

テストの目的で、DEPTテーブル(孫の依存関係を含む)も参照するいくつかの新しいテーブルをSCOTTスキーマに追加しました。

SQL> create table dept_child2 (
  2  deptno number references dept( deptno )
  3  );

Table created.

SQL> create table dept_child3 (
  2    dept_child3_no number primary key,
  3    deptno number references dept( deptno )
  4  );

Table created.

SQL> create table dept_grandchild (
  2    dept_child3_no number references dept_child3( dept_child3_no )
  3  );

Table created.

クエリが期待される出力を返したことを確認しました

SQL> ed
Wrote file afiedt.buf

  1  select parent, child, level from (
  2  select parent_table.table_name parent, child_table.table_name child
  3   from user_tables      parent_table,
  4        user_constraints parent_constraint,
  5        user_constraints child_constraint,
  6        user_tables      child_table
  7  where parent_table.table_name = parent_constraint.table_name
  8    and parent_constraint.constraint_type IN( 'P', 'U' )
  9    and child_constraint.r_constraint_name = parent_constraint.constraint_name
 10    and child_constraint.constraint_type   = 'R'
 11    and child_table.table_name = child_constraint.table_name
 12    and child_table.table_name != parent_table.table_name
 13  )
 14  start with parent = 'DEPT'
 15* connect by prior child = parent
SQL> /

PARENT                         CHILD                               LEVEL
------------------------------ ------------------------------ ----------
DEPT                           DEPT_CHILD3                             1
DEPT_CHILD3                    DEPT_GRANDCHILD                         2
DEPT                           DEPT_CHILD2                             1
DEPT                           EMP                                     1
于 2008-09-17T22:34:58.850 に答える
2

これを行う最も簡単な方法は、すべての FK 情報を単純な 2 列 (親、子) テーブルにコピーしてから、次のアルゴリズムを使用することです。

while (rows left in that table)
  list = rows where table name exists in child but not in parent
  print list
  remove list from rows

それで全部です。基本的に、最初に何にも依存しないすべてのノードを出力して削除します。それが完了すると、他のいくつかのノードが解放され、プロセスを繰り返すことができます。

PS最初のリストに自己参照テーブルを挿入しないようにしてください(子=親)

于 2008-09-17T22:11:40.233 に答える