문제

테이블 사이의 외래 키를 기반으로 테이블의 종속성 그래프를 작성하려고 합니다.이 그래프는 임의의 테이블 이름을 루트로 시작해야 합니다.테이블 이름이 주어지면 all_constraints 뷰를 사용하여 이를 참조하는 테이블을 찾은 다음 이를 참조하는 테이블을 찾는 등의 작업을 수행할 수 있지만 이는 매우 비효율적입니다.모든 테이블에 대해 이 작업을 수행하는 재귀 쿼리를 작성했지만 다음을 추가하면 다음과 같습니다.

START WITH Table_Name=:tablename

전체 트리를 반환하지 않습니다.

도움이 되었습니까?

해결책

    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

다른 팁

이를 수행하는 가장 간단한 방법은 모든 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

그게 다야.기본적으로 먼저 어떤 것에도 의존하지 않는 모든 노드를 인쇄하고 제거합니다.해당 작업이 완료되면 일부 다른 노드가 해제되며 프로세스를 반복할 수 있습니다.

추신초기 목록(자식=부모)에 자체 참조 테이블을 삽입하지 않도록 하세요.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top