Listar dependencias de uma tabela, recursivamente

Dúvidas, dicas e truques de PL/SQL. Aqui também vão assuntos relacionados a pacotes, triggers, funções, Java-Stored Procedures, etc
Responder
gilbertoca
Rank: DBA Sênior
Rank: DBA Sênior
Mensagens: 372
Registrado em: Ter, 24 Jan 2006 3:33 pm
Localização: Palmas - TO
Contato:

Olá!
Estou precisando de algumas dicas!
Estou realizando algumas atividades de carga legada em nosso banco e inicialmente estou desabilitando todas as restrições das tabelas no processo de limpeza, antes de uma carga.
Isto demora muito e na verdade não há a necessidade de fazer-lo para todas as tabelas do banco. Então resolvi me aventurar no plsql!
A ideia era realmente simples, fazer um cursor onde passo o nome da tabela como parametro. Dai faço um loop nesta lista e para cada item faço de novo a mesma chamda ao curso com o nome da tabela depedente (recursivamente). De repente surgiu este codigo:

Selecionar tudo

declare
PROCEDURE list_dependences(
  p_table_name  IN user_constraints.table_name%TYPE)
IS
  CURSOR id_fkeys (
    c_table_name user_constraints.table_name%TYPE)
  IS
  SELECT table_name, constraint_name fkey, r_constraint_name pkey, status
  FROM user_constraints
  WHERE constraint_type='R'
    AND r_constraint_name IN (
      SELECT constraint_name
      FROM user_constraints
      WHERE table_name=c_table_name
        AND constraint_type='P')
  ORDER BY table_name, constraint_name;
  -- record variables
rec_id_fkeys id_fkeys%ROWTYPE;
begin
   OPEN id_fkeys(p_table_name);
      DBMS_OUTPUT.put_line('LISTA DEPENDENCIAS:'||p_table_name);
    LOOP -- process foreign keys
      FETCH id_fkeys INTO rec_id_fkeys;
      EXIT WHEN id_fkeys%NOTFOUND;
      DBMS_OUTPUT.put_line(rec_id_fkeys.table_name || ' ' ||
                ' CONSTRAINT ' || rec_id_fkeys.fkey);
      list_dependences(rec_id_fkeys.table_name);
    END LOOP; -- process foreign keys
end;    
begin
  list_dependences('VINCULOS');
END;
Mas parece não ser tão simple assim! Na primeira execução, acabei excedendo o buffer do DBMS_OUTUP.PUT_LINE. Na segunda vez(depois de desabilitar o dbms_output) estoura o limite de cursores abertos.
Bom, acho que vocês pegaram a ideia!
Alguém pode me auxiliar neste problema?
Gilberto
erthal
Rank: Analista Sênior
Rank: Analista Sênior
Mensagens: 130
Registrado em: Seg, 22 Nov 2004 1:45 pm
Localização: Niterói - RJ

Gilberto,

Não sou expert em PL, mas vamos lá. Tente assim:

Selecionar tudo

PROCEDURE list_dependences(p_status IN) is

BEGIN
FOR R1 IN (SELECT table_name
                            ,constraint_name    fkey
                            ,status
                 FROM    user_constraints
                 WHERE  constraint_type='R'
                 AND      r_constraint_name IN 
                            (SELECT constraint_name
                             FROM    user_constraints
                             WHERE  constraint_type='P')
                 ORDER BY table_name, constraint_name) LOOP
        --     
        IF P_STATUS = 'ENABLE' THEN
            EXECUTE IMMEDIATE('ALTER TABLE '||R1.TABLE_NAME||' DISABLE '||R1.FKEY);
        END IF;
        --
        IF R1.STATUS = 'DISABLED' THEN
            EXECUTE IMMEDIATE('TRUNCATE TABLE '||R2.TABLE_NAME);
        END IF;
        --
END LOOP;
END;
Cara, acredito que assim você poderá desabilitar todas as constraints, apesar da demora, e ainda por cima truncar as tabelas.

Só não pude testar porque estou sem banco, mas acho que vai funcionar.

Abs,
Gustavo.
gilbertoca
Rank: DBA Sênior
Rank: DBA Sênior
Mensagens: 372
Registrado em: Ter, 24 Jan 2006 3:33 pm
Localização: Palmas - TO
Contato:

Oi Gustavo! Beleza!

Como disse no post anterior, isto eu já faço e demora muito. Alem de disso eu não preciso truncar todas as tabelas!
O que estou tentando fazer é baseado no nome de uma tabela que passo como parametro, truncar todas as suas dependencias e das dependencias as dependencias delas e assim vai (recursivamente):

Exemplo:

Selecionar tudo

tabela1
    filha1
    filha2
        temfilha1
        temfilha2
           comsobrinho
    filha3
        comfilho1
Agora quero truncar filha3 somente. Somente truncaria comfilho1 e filha3. Ou truncar filha2 o qual truncaria comsobrinho, temfilha2, temfilha1 e finalmente filha2.

Entendeu?
Obrigado pela ajuda!
Gilberto
erthal
Rank: Analista Sênior
Rank: Analista Sênior
Mensagens: 130
Registrado em: Seg, 22 Nov 2004 1:45 pm
Localização: Niterói - RJ
Gustavo Erthal Jr. | TRISCAL
...................................................
Rio de Janeiro | (21) 2507-2010
São Paulo | (11) 3167-0526
www.triscal.com.br

Gilberto,

Mas o truncate não funciona quando as FKs estão habilitadas

Gustavo.
gilbertoca
Rank: DBA Sênior
Rank: DBA Sênior
Mensagens: 372
Registrado em: Ter, 24 Jan 2006 3:33 pm
Localização: Palmas - TO
Contato:

Mas o truncate não funciona quando as FKs estão habilitadas

Gustavo.
Isso eu sei! E quando terminar o codigo, que agora não faz nada (apenas testando), vou desabilitar os gatilhos, as restrições, fazer o truncamento e finalmente habilitar as restriçoes os gatilhos novamente.

Pegou agora?

Gilberto
erthal
Rank: Analista Sênior
Rank: Analista Sênior
Mensagens: 130
Registrado em: Seg, 22 Nov 2004 1:45 pm
Localização: Niterói - RJ

Entender eu entendi.

Então porque você não tenta usar um variável do tipo varchar2 ou lob pra armazenar a saída?

Abs,
Gustavo.
HenriqueMachado
Rank: Programador Sênior
Rank: Programador Sênior
Mensagens: 48
Registrado em: Seg, 29 Mai 2006 1:24 pm
Localização: Blumenau - SC
Abraços,
Henrique Machado Muller

Bom tenho um codigo aqui que pode ser util.

Primeiro eu crio uma view para facilitar

Selecionar tudo

CREATE OR REPLACE VIEW V_DISABLE_CONTRAINT
(COMANDO, TABLE_NAME, TABLE_R, ORDERM)
AS 
select comando, TABLE_NAME , TABLE_R,  orderm 
     from ( 
           SELECT 'ALTER TABLE '||A1.TABLE_NAME||' disable constraint '||A1.CONSTRAINT_NAME||' keep index;--1' comando 
                           , a2.table_name 
																											, a1.TABLE_NAME TABLE_R
                          , 1 orderm 
             FROM  USER_CONSTRAINTS A1, USER_CONS_COLUMNS A2 
            WHERE  A1.r_constraint_name  = A2.CONSTRAINT_NAME 
            UNION ALL 
           SELECT 'ALTER TABLE '||A1.TABLE_NAME||' disable constraint '||A1.CONSTRAINT_NAME||' keep index;--2' comando 
                           , a1.table_name 
																											, '' TABLE_R
                           , 2 orderm 
             FROM  USER_CONSTRAINTS A1, USER_CONS_COLUMNS A2 
            WHERE  A1.constraint_name  = A2.CONSTRAINT_NAME 
            UNION ALL 
                          
           SELECT 'truncate table ' || table_name || ';-- 3' comando 
                   ,table_name 
																				, '' TABLE_R
                  ,3 orderm 
             from user_tables 
            UNION ALL 
                      
           SELECT 'ALTER TABLE '||A1.TABLE_NAME||' enable novalidate constraint '||A1.CONSTRAINT_NAME||';--5' comando 
                           , a1.table_name
																												, '' TABLE_R 
                           , 5 orderm 
             FROM  USER_CONSTRAINTS A1, USER_CONS_COLUMNS A2 
            WHERE  A1.constraint_name  = A2.CONSTRAINT_NAME 
                          and a1.CONSTRAINT_TYPE IN ('P','C') 
           UNION ALL 
           SELECT 'ALTER TABLE '||A1.TABLE_NAME||' enable novalidate constraint '||A1.CONSTRAINT_NAME||';--6' comando 
                           , a1.table_name
																												, '' TABLE_R 
                           , 6 orderm 
             FROM  USER_CONSTRAINTS A1, USER_CONS_COLUMNS A2 
            WHERE  A1.constraint_name  = A2.CONSTRAINT_NAME 
                          and a1.CONSTRAINT_TYPE NOT IN ('P','C') 
           UNION ALL 
           SELECT 'ALTER TABLE '||A1.TABLE_NAME||' enable novalidate constraint '||A1.CONSTRAINT_NAME||';--7' comando 
                           , a2.table_name
																												, '' TABLE_R 
                           , 7 orderm 
             FROM USER_CONSTRAINTS A1, USER_CONS_COLUMNS A2 
            WHERE A1.r_constraint_name  = A2.CONSTRAINT_NAME 
          )
Note que uso o comando "keep index" quando desabilito a tabela, para que o index referenciado pela constraint não seja destruido. Apenas será reatualizado quando ligar novamente a contraint.

Depois o select
Com o select você terá dependencias até 2 niveis

Selecionar tudo


SELECT   *
    FROM v_DISABLE_CONTRAINT
   WHERE TABLE_NAME IN (SELECT TABLE_R from v_DISABLE_CONTRAINT WHERE TABLE_NAME IN (TABELA))
ORDER BY orderm

Outra coisa importante é :
se você executar o codigo como esta ai em cima(criação da view)
Demorar um monte, uma dica para ajudar é criar tabelas temporárias em vez de usar a view do oracle, por exemplo como o codigo ai em baixo

Selecionar tudo

create table t_USER_CONSTRAINTS as select CONSTRAINT_NAME, CONSTRAINT_TYPE ,TABLE_NAME, R_CONSTRAINT_NAME from USER_CONSTRAINTS;
create table t_USER_CONS_COLUMNS as select * from USER_CONS_COLUMNS;

Espero ter ajudado
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Isso vai ser de grande utilidade por aqui :-)

Obrigado!!! :-o
Responder
  • Informação
  • Quem está online

    Usuários navegando neste fórum: Nenhum usuário registrado e 16 visitantes