Pergunta

Eu estou tentando construir um gráfico de dependência de tabelas com base nas chaves estrangeiras entre eles. Este gráfico tem de começar com um nome de tabela arbitrária como sua raiz. Eu poderia, dado um olhar nome da tabela se as tabelas que fazem referência a ele usando os all_constraints vista, em seguida, procurar as tabelas que referenciá-los, e assim por diante, mas isso seria horrível ineficiente. Eu escrevi uma consulta recursiva que faz isso para todas as tabelas, mas quando eu adiciono:

START WITH Table_Name=:tablename

Não devolve a árvore inteira.

Foi útil?

Solução

    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

deve funcionar (substitua o nome da tabela, é claro), assumindo que tudo está no mesmo esquema. Use as versões DBA_ das tabelas de dicionário de dados e as condições para as colunas proprietário ea R_OWNER se você precisa lidar com dependências cross-esquema. Em uma reflexão mais aprofundada, este não leva em conta as restrições auto-referenciais (ou seja, uma restrição na tabela EMP que as referências de coluna MGR A coluna NUM_EMP) ou, então você teria que modificar o código para lidar com esse caso, se você precisa lidar com restrições auto-referenciais.

Para fins de teste, eu adicionei algumas novas tabelas para o esquema SCOTT que também referência tabela DEPT (incluindo uma dependência neto)

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.

e verificou-se que a consulta retornou a saída esperada

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

Outras dicas

Mais simples maneira de fazer isso é copiar todas as informações FK em uma simples, 2-coluna (pais, filhos) mesa, e, em seguida, usar o seguinte algoritmo:

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

isso é tudo. Basicamente, você primeiro imprimir e remover todos os nós que não dependem de qualquer coisa. Depois que está sendo feito, alguns outros nós vai ficar livre e você pode repetir o processo.

P.S. Certifique-se de não inserir tabelas de auto-referência na lista inicial (criança = pai)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top