深く調査した後、すべてのテーブルを処理し、階層内のテーブルの最大レベルを取得する独自のバージョンを作成しました(親子関係のないテーブルも考慮に入れて、すべてのスキーマを読み取り、ルートとともにレベル1になります)もの)。アクセスできる場合は、all_の代わりにdba_テーブルを使用してください。
WITH hier AS (
SELECT child_table owner_table_name
, LEVEL lvl
, LPAD (' ', 4 * (LEVEL - 1)) || child_table indented_child_table
, sys_connect_by_path( child_table, '|' ) tree
FROM (
/*----------------------------------------------------------------------*/
/* Retrieve all tables. Set them as the Child column, and set their */
/* Parent Column to NULL. This is the root list (first iteration) */
/*----------------------------------------------------------------------*/
SELECT NULL parent_table
, a.owner || '.' || a.table_name child_table
FROM all_tables a
UNION
/*----------------------------------------------------------------------*/
/* List of all possible Parent-Child relations. This table is used as */
/* a link list, to link the current iteration with the next one, from */
/* root to last child (last child is what we are interested to find). */
/*----------------------------------------------------------------------*/
SELECT p.owner || '.' || p.table_name parent_table
, c.owner || '.' || c.table_name child_table
FROM all_constraints p, all_constraints c
WHERE p.owner || '.' || p.constraint_name = c.r_owner || '.' || c.r_constraint_name
AND (p.constraint_type = 'P' OR p.constraint_type = 'U')
AND c.constraint_type = 'R'
)
START WITH parent_table IS NULL
/*----------------------------------------------------------------------*/
/* NOCYCLE prevents infinite loops (i.e. self referencing table constr) */
/*----------------------------------------------------------------------*/
CONNECT BY NOCYCLE PRIOR child_table = parent_table
)
SELECT *
FROM hier
WHERE (owner_table_name, lvl) IN ( SELECT owner_table_name
, MAX(lvl)
FROM hier
GROUP BY owner_table_name
);
編集:無限ループを見つけるとき、このクエリには「一種の」問題があります。
このツリーがある場合:
b --> c --> d
b <-- c
レベル2をcに次のように割り当てb --> c
、レベル2をbに次のように割り当てます。c --> b
dの場合、検出するb --> c --> d
ため、レベル3が割り当てられます。
ご覧のとおり、問題はループの内側にあり、外側からの値は常に最大の正しいレベルになります