Oi, Giovanni : então, como eu disse nós, mais experientes em tecnologia Oracle, é que temos que orientar o cliente, faz parte do nosso trabalho, jamais aceitar o que eles dizem sem questionamento... No caso específico, eles estão falando ** BOBAGEM **, pura e simples : primeiro, o que ocorre é que NÃO É qquer DDL que invalida a trigger (apenas os que adicionam/diminuem/removem colunas)- pra cobrir o caso de coluna removida da tabela-origem vc simplesmente usa INSERT da trigger a sintaxe :
INSERT INTO tabelaaudit VALUES (:old.coluna1, :old.coluna2..., :old.colunaN), que aí se removerem colunas o trigger fica inválido, e quando uma trigger de DML fica inválida, o DML (o DELETE no caso) vai ** BOMBAR **, vai ABORTAR, vai dar pau, com uma mensagem BEM clara de trigger invalid - Não tem Como eles esquecerem, pois o DELETE não funcionará, a aplicação vai dar pau... Absolutamente não é o caso de que a auditoria vai falhar, se a trigger ficou inválida é a própria aplicação que vai parar, penso eu que não tem como vc "esquecer" , certo ? Já no caso de adicionarem uma coluna na tabela-origem , pra começo de conversa num ambiente regrado e Organizado alterações de modelo deveriam ser RARAS e sempre feitas por um DBA, mas se mesmo assim for desejado/considerado útil, foi JUSTAMENTE pra situações como essa que se criou no RDBMS Oracle a trigger de DDL, que dispara quando um DDL é efetuado : nessa trigger vc tanto poderia disparar um job que adiciona a nova coluna na tabela de audit, quanto (o que seria mais correto, acho eu) poderia na trigger de DDL feito na tabela-origem comparar a estrutura dela (na DBA_TABLEs, USER_TABLES, o que for) contra a estrutura da outra tabela , abortando com RAISE_APPLICATION_ERROR se antes de fazer a inclusão na tabela-origem o cara não incluiu na tabela de audit... Essas verificações de DDL (que, como eu disse, num ambiente Organizado são redundantes, não é qquer zémané que pode fazer DDL) tornariam o código necessário pra usar triggers um pouquinho mais complexo, mas nada do outro mundo, é uma meia dúzia de linhas, tipo assim, e IMHO ainda seria preferível, pois manteria-se as vantagens da trigger (ie, de auditar QUALQUER delete na tabela, não só os vindos da sua procedure, de ser transacional, etc, etc, veja tudo que foi dito no e-mail anterior.... ===> CASO realmente o cliente insista mesmo na solução de código dentro da sua procedure, UMA VEZ que vc esteja Absolutamente, Totalmente, Positivamente CERTO de que ele entendeu as desvantagens E os riscos do código procedural, aí sim vc faria as alterações indicadas lá pelo Paulo (savepoints), E faria o tratamento de erros , via EXCEPTIOn, tal como eu indiquei... []s Chiappa --- Em oracle_br@yahoogrupos.com.br, "Giovanni Ferreira de Sousa" <giovanni.sousa@...> escreveu > > Obrigado pela explanação Paulo e Chiapa, > > Chiapa, > Quando o cliente me solicitou isso, eu sugeri o uso de trigger como vc acabou > de dizer, mas eles disseram que não usam TRIGGERS porque se houver algum DDL > na tabela onde a TRIGGER é disparada invalida a TRIGGER e que eles não > lembrariam de atualizar a TRIGGER e a auditoria seria falha. Sendo assim, > estou fazendo conforme eles solicitaram. > Qual a sua melhor sugestão para este caso? > Segue a PROCEDURE que sugeri. > A aplicação se encarrega de passar os parâmetros... > > CREATE OR REPLACE PROCEDURE DBSISMAC.sp_solicitacao_remanej_final ( > estado IN NUMBER, > usuario IN NUMBER, > competencia IN NUMBER, > DS_USERNAME IN VARCHAR2) > IS > BEGIN > INSERT INTO DBSISMAC.TL_TMQUADRO_01 > SELECT competencia AS NU_COMPETENCIA_SOLICITACAO, > CO_MUNICIPIO_IBGE, > VL_POP_PROPRIA_AMB, > VL_POP_REFERENCIA_AMB, > VL_POP_PROPRIA_HOSP, > VL_POP_REFERENCIA_HOSP, > VL_INCENTIVO_PERMANENTE, > VL_ENC_OUTRA_UF, > VL_REC_OUTRA_UF, > VL_AJUSTE, > VL_TOTAL_PPI_ASSISTENCIAL, > CO_PROTOCOLO, > CO_USUARIO, > DT_ALTERACAO, > DS_USERNAME AS DS_USERNAME, > 'EXCLUÍDO' AS DS_OPERACAO, > SYSDATE AS DT_OPERACAO > FROM DBSISMAC.TM_QUADRO_01 > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > > DELETE FROM DBSISMAC.TM_QUADRO_01 > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > > INSERT INTO DBSISMAC.TL_TMQUADRO_02 > SELECT CO_MUNICIPIO_IBGE, > NO_ESPECIFICACAO, > VL_TOTAL_PPI_ASSISTENCIAL, > CO_PROTOCOLO, > competencia AS NU_COMPETENCIA_SOLICITACAO, > CO_USUARIO, > DT_ALTERACAO, > DS_USERNAME AS DS_USERNAME, > 'EXCLUÍDO' AS DS_OPERACAO, > SYSDATE AS DT_OPERACAO > FROM DBSISMAC.TM_QUADRO_02 > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > > DELETE FROM DBSISMAC.TM_QUADRO_02 > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > > INSERT INTO DBSISMAC.TL_TMQUADRO_03 > SELECT competencia AS NU_COMPETENCIA_SOLICITACAO, > CO_MUNICIPIO_IBGE_ORIG, > CO_MUNICIPIO_IBGE_EXEC, > VL_GEST_ESTADUAL, > VL_GEST_MUNICIPAL, > VL_TOTAL_PPI_ASSISTENCIAL, > CO_PROTOCOLO, > CO_USUARIO, > DT_ALTERACAO, > DS_USERNAME AS DS_USERNAME, > 'EXCLUÍDO' AS DS_OPERACAO, > SYSDATE AS DT_OPERACAO > FROM DBSISMAC.TM_QUADRO_03 > WHERE SUBSTR (CO_MUNICIPIO_IBGE_ORIG, 0, 2) = estado; > > DELETE FROM DBSISMAC.TM_QUADRO_03 > WHERE SUBSTR (CO_MUNICIPIO_IBGE_ORIG, 0, 2) = estado; > > INSERT INTO DBSISMAC.TL_TMQUADRO_04 > SELECT competencia AS NU_COMPETENCIA_SOLICITACAO, > CO_MUNICIPIO_IBGE, > CO_CNES, > NO_UNIDADE, > NU_TERMO, > DT_PUBLIC_EXT_TERMO, > CO_FUNDO, > VL_TOTAL_FS, > CO_PROTOCOLO, > CO_USUARIO, > DT_ALTERACAO, > DS_USERNAME AS DS_USERNAME, > 'EXCLUÍDO' AS DS_OPERACAO, > SYSDATE AS DT_OPERACAO > FROM DBSISMAC.TM_QUADRO_04 > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > > DELETE FROM DBSISMAC.TM_QUADRO_04 > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > > INSERT INTO DBSISMAC.TL_TMQUADRO_05 > SELECT competencia AS NU_COMPETENCIA_SOLICITACAO, > CO_MUNICIPIO_IBGE, > VL_TOTAL_FES, > CO_PROTOCOLO, > CO_USUARIO, > DT_ALTERACAO, > DS_USERNAME AS DS_USERNAME, > 'EXCLUÍDO' AS DS_OPERACAO, > SYSDATE AS DT_OPERACAO > FROM DBSISMAC.TM_QUADRO_05 > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > > DELETE FROM DBSISMAC.TM_QUADRO_05 > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > > INSERT INTO DBSISMAC.TL_TMQUADRO_06 > SELECT competencia AS NU_COMPETENCIA_SOLICITACAO, > CO_GESTAO, > CO_MUNICIPIO_IBGE, > CO_CNES, > NO_UNIDADE, > NU_CONTRATO, > DT_PUBLIC_EXT_CONTRATO, > VL_TOTAL_FNS, > CO_PROTOCOLO, > CO_USUARIO, > DT_ALTERACAO, > DS_USERNAME AS DS_USERNAME, > 'EXCLUÍDO' AS DS_OPERACAO, > SYSDATE AS DT_OPERACAO > FROM DBSISMAC.TM_QUADRO_06 > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > DELETE FROM DBSISMAC.TM_QUADRO_06 > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > commit; > > exception when others then > rollback; > END; > / > > > Giovanni > > > ________________________________ > > De: oracle_br@yahoogrupos.com.br em nome de José Laurindo > Enviada: qui 29/12/2011 11:06 > Para: oracle_br@yahoogrupos.com.br > Assunto: [oracle_br] Re: Tratamento de logs > > > > > Paulo, é absolutamente verdade que a maneira de desfazer apenas parte dos > comandos da transação é o SAVEPOINT - no caso em questão, porém, uma solução > procedural, além de ser mais longa, só vai ser disparada (óbvio) quando da > execução do PL/SQL, se outras rotinas/programas fizerem DELETEs na tabela > esses DELETEs passam SEM LOGS, e uma Auditoria em princípio deve pegar TODOS > os DMLs, independente de onde venham... Outra coisa é que o %rowcount pega os > casos de delete que não encontrou dados, MAS casos de erro efetivo no DELETE > (por exemplo, tentativa de eliminar PK com filhos presentes) ele não pega, > faltaria adicionar os EXCEPTIONS... > > Juntando isso com a necessidade (estranha, mas é um dado do problema) de só > auditar DELETEs bem-sucedidos, eu optaria por um TRIGGER DE DML, assim : > > create or replace trigger TRG_AUD_DEL after DELETE on nomedatabela > FOR EACH ROW > BEGIN > insert into tabeladelog(coluna1, coluna2, ... colunaN) > values(:old.coluna1, :old.coluna2, ... :old.colunaN); > END; > > ==> aí, além do código ser menor, a "auditoria" vai pegar QUALQUER DELETE na > tabela, seja ou não vindo do PL/SQL, como a trigger é AFTER (depois, em > inglês), ela automagicamente só dispara ** DEPOIS ** de um DELETE bem > sucedido, aí vc não precisa se preocupar no seu código de auditoria com > COMMITs/ROLLBACKs e ainda é transacional, ie, se depois do delete feito OK > alguém pedir ROLLBACK do DELETE a inserção na tabela de log não é registrada > - o colega não diz se isso é preciso mas pelo jeitão parece que sim ... > > Aliás, Giovani, coisas do tipo (ah, o que deve ser logado / o que deve > ocorrer ocorre se neguinho pedir ROLLBACK de um DELETE bem-sucedido, o que > deve ocorrer se alguém fazer DELETE fora do seu programa, o que deve ocorrer > se duas sessões pedirem DELETE do mesmo registro , etc, etc) é nossa parte, > enquanto técnicos especialistas em banco de dados, ter bem claro : o seu > Cliente com quase 100% de certeza não faz a MENOR IDÉIA dessas coisas, nem > imagina que o banco é MULTI-USUÁRIO, que podem haver erros de DELETE , etc, > então quando ele te pede "ah, me faz um log", é um des-serviço vc não o > avisar dessas coisas , não esclarecer bem a necessidade, o que ele quer que > aconteça em cada caso ... > > []s > > Chiappa > > --- Em oracle_br@yahoogrupos.com.br <mailto:oracle_br%40yahoogrupos.com.br> , > Paulo Petruzalek <ppetruzalek@> escreveu > > > > Complementando: acabei deixando na pressa o commit fora do if: > > > > If sql%rowcount = 0 then > > rollback; > > else > > commit; > > end if; > > > > Mas uma solução sem commits (dentro da sp) pode ser obtida com savepoints: > > > > begin > > savepoint A; > > insert into ... > > delete from ... > > if sql%rowcount = 0 then > > rollback to A; > > end if; > > end; > > / > > > > Neste caso o controle da transação ficará por conta do código chamador, sem > > o risco de commitar algo que não devia. > > > > Paulo > > > > --- Em qua, 28/12/11, Paulo Petruzalek <ppetruzalek@> escreveu: > > > > De: Paulo Petruzalek <ppetruzalek@> > > Assunto: Re: [oracle_br] Tratamento de logs > > Para: oracle_br@yahoogrupos.com.br <mailto:oracle_br%40yahoogrupos.com.br> > > Data: Quarta-feira, 28 de Dezembro de 2011, 22:27 > > > > Se for para tratar o caso de onde o delete não ocorre, basta fazer um: > > > > if sql%rowcount = 0 then > > rollback; > > end if; > > > > Agora no caso de "dar pau", você vai ter que instrumentar o código com um > > bloco exception. Exemplo simplificado: > > > > begin > > insert into log values (...) ; > > delete from tabela where x = ...; > > if sql%rowcount = 0 then rollback; > > end if; > > commit; > > > > exeception > > when others then rollback; > > end; > > / > > > > Talvez seja mais elegante declarar uma exceção e lançar ela no caso do > > sql%rowcount ser igual a 0... mas enfim, o estilo de código fica por sua > > conta e/ou pelas regras do seu projeto. > > > > Também note que deixar controle de transações (commit / rollback) dentro de > > uma sp pode causar muitos problemas se esta for chamada por outras sps. Eu > > não necessariamente usaria esta abordagem, só fiz o exemplo assim para > > ficar compatível com o seu código. > > > > Paulo > > > > --- Em qua, 28/12/11, Giovanni Ferreira de Sousa <giovanni.sousa@> escreveu: > > > > De: Giovanni Ferreira de Sousa <giovanni.sousa@> > > Assunto: [oracle_br] Tratamento de logs > > Para: oracle_br@yahoogrupos.com.br <mailto:oracle_br%40yahoogrupos.com.br> > > Data: Quarta-feira, 28 de Dezembro de 2011, 10:56 > > > > Bom Dia galera, > > > > > > Estou com a seguinte situação aqui no trabalho: > > > > Um usuário solicitou que para as deleções físicas no banco, esses registros > > deletado deveriam ser armazendos em uma tabela de log. No schema da > > aplicação existe uma procedure que faz o delete nas tabelas. Para atender a > > demanda do usuário foi adicionado na procedure o insert na tabela de log, > > baseado no registro que será deletado, como segue no exemplo abaixo. Sendo > > assim gostaria da ajuda de vocês para o seguinte: > > > > Após o INSERT é feito o DELETE. > > > > SE o DELETE der PAU ou não for feito. Como faço pra dar ROLLBACK(no INSERT > > anterior)? > > > > > > > > CREATE OR REPLACE PROCEDURE DBSISMAC.sp_solicitacao_remanej_final ( > > estado IN NUMBER, > > usuario IN NUMBER, > > competencia IN NUMBER, > > DS_USERNAME IN VARCHAR2) > > IS > > BEGIN > > INSERT INTO DBSISMAC.TL_TMQUADRO_06 > > SELECT competencia AS NU_COMPETENCIA_SOLICITACAO, > > CO_GESTAO, > > CO_MUNICIPIO_IBGE, > > CO_CNES, > > NO_UNIDADE, > > NU_CONTRATO, > > DT_PUBLIC_EXT_CONTRATO, > > VL_TOTAL_FNS, > > CO_PROTOCOLO, > > CO_USUARIO, > > DT_ALTERACAO, > > DS_USERNAME AS DS_USERNAME, > > 'EXCLUÍDO' AS DS_OPERACAO, > > SYSDATE AS DT_OPERACAO > > FROM DBSISMAC.TM_QUADRO_06 > > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > > > > DELETE FROM DBSISMAC.TM_QUADRO_06 > > WHERE SUBSTR (CO_MUNICIPIO_IBGE, 0, 2) = estado; > > COMMIT; > > END; > > / > > > > Atenciosamente, > > > > Giovanni > > > > > > [As partes desta mensagem que não continham texto foram removidas] > > > > > > > > ------------------------------------ > > > > ---------------------------------------------------------- > > >Atenção! As mensagens do grupo ORACLE_BR são de acesso público e de > > >inteira responsabilidade de seus remetentes. > > Acesse: http://www.mail-archive.com/oracle_br@yahoogrupos.com.br/ > > ---------------------------------------------------------- > > >Apostilas » Dicas e Exemplos » Função » Mundo Oracle » Package » Procedure > > >» Scripts » Tutoriais - O GRUPO ORACLE_BR TEM SEU PROPRIO ESPAÇO! VISITE: > > >http://www.oraclebr.com.br/ > > ---------------------------------------------------------- Links do Yahoo! > > Grupos > > > > > > > > > > [As partes desta mensagem que não continham texto foram removidas] > > > > > > > > ------------------------------------ > > > > ---------------------------------------------------------- > > >Atenção! As mensagens do grupo ORACLE_BR são de acesso público e de > > >inteira responsabilidade de seus remetentes. > > Acesse: http://www.mail-archive.com/oracle_br@yahoogrupos.com.br/ > > ---------------------------------------------------------- > > >Apostilas » Dicas e Exemplos » Função » Mundo Oracle » Package » Procedure > > >» Scripts » Tutoriais - O GRUPO ORACLE_BR TEM SEU PROPRIO ESPAÇO! VISITE: > > >http://www.oraclebr.com.br/ > > ---------------------------------------------------------- Links do Yahoo! > > Grupos > > > > > > > > > > [As partes desta mensagem que não continham texto foram removidas] > > > > > > > > > [As partes desta mensagem que não continham texto foram removidas] >