Trigger de INSTRUÇÃO - como capturar os dados inseridos

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
GilberttJR
Rank: Estagiário Sênior
Rank: Estagiário Sênior
Mensagens: 8
Registrado em: Sex, 26 Out 2007 9:33 am
Localização: São Paulo

Olá pessoal . Tudo bem ?

O negócio é o seguinte:
Gostaria de saber como faço para recuperar dentro de uma trigger de INSTRUÇÃO, os valores das linhas que foram inseridas através de um INSERT.

Eu sei que é possível fazer isto através da trigger de LINHA. Usando o :NEW.campoDesejado dentro da trigger. Mas não posso usar a trigger de LINHA porque ela vai ser chamada para cada linha inserida depois de chamada a instrução "INSERT bla bla bla..."

Eu preciso que, dado um INSERT que faça a inserção de várias linhas, a trigger seja chamada uma unica vez após ter sido realizado todos os inserts .Na verdade eu preciso que a tabela que tem a trigger associada a ela, seja liberada totalmente, porque eu terei que usar esta mesma tabela dentro da sua própria trigger para fazer um SELECT nela. Na triger de linha eu não consigo fazer isto.

No MSSQL server é possível fazer algo semelhlante porque dentro da trigger os valores que acabaram de ser inseridos ficam armazenados numa espécie de tabela temporária chamada INSERTED, deixando a tabela onde foram inseridas as linhas, livre para que eu possa usá-la num SELECT por exemplo, dentro da trigger.

Será qie fui claro ?
Se vocês entenderam , alguém poderia me ajudar ?
Trevisolli
Moderador
Moderador
Mensagens: 2016
Registrado em: Qua, 12 Jan 2005 3:25 pm
Localização: Araraquara - SP
Abraço,

Trevisolli
OCA Oracle PL/SQL Developer Certified Associate
OCP Oracle Forms Developer Certified Professional
Araraquara-SP

Brother,

você quer realizar alguma ação, após inserir "todos" os registros na base?
Seria uma trigger de Statement?

Dá uma olhada neste link aqui da Própria Oracle:
GilberttJR
Rank: Estagiário Sênior
Rank: Estagiário Sênior
Mensagens: 8
Registrado em: Sex, 26 Out 2007 9:33 am
Localização: São Paulo

olá trevisolli.

Com relação as duas questoes :
1) Sim, eu quero realizar uma ação após inserir todos os registros na tabela.
2) Sim, é uma trigger de Statatement

Porém , dentro desta trigger eu preciso ter acesso a todos os dados novos inseridos. Precisaria capturar estes dados num CURSOR, ou algo que me possibilite utiliza-los dentro da trigger.
E também vou precisar fazer (dentro desta mesma trigger) um select de outros dados que estão contidos nesta mesma tabela que eu acabei de fazer o insert.

você teria alguma sugestão de como eu poderia fazer isto ?

Fico grato pela atenção.
Trevisolli
Moderador
Moderador
Mensagens: 2016
Registrado em: Qua, 12 Jan 2005 3:25 pm
Localização: Araraquara - SP
Abraço,

Trevisolli
OCA Oracle PL/SQL Developer Certified Associate
OCP Oracle Forms Developer Certified Professional
Araraquara-SP

Brother,

Seguinte,

Criei uma tabela de teste e, criei tb a trigger abaixo:

TABELA: Teste

Selecionar tudo

  ID      NUMBER;
  NOME VARCHAR2(100);

Selecionar tudo

CREATE OR REPLACE TRIGGER TRG_TESTE_01
 AFTER 
 INSERT
 ON TESTE
 REFERENCING OLD AS OLD NEW AS NEW
DECLARE
	V_TESTE NUMBER(10);
BEGIN
	SELECT COUNT(1)
	 INTO V_TESTE
	 FROM TESTE;

EXCEPTION
 WHEN OTHERS THEN
	  RAISE_APPLICATION_ERROR(-20001, 'Erro Trigger: ' || SQLERRM  );
END;
/
Verifiquei que com o Select, não disparou mutante, portanto, realize um teste pro teu caso e, qualquer coisa, posta aqui.
rogenaro
Rank: DBA Pleno
Rank: DBA Pleno
Mensagens: 232
Registrado em: Sex, 30 Mar 2007 7:26 pm
Localização: Londrina - PR
Rafael O. Genaro

Uma maneira de realizar isto seria:
1º criar uma package para armazenar as chaves das linhas que acabaram de ser inseridas em uma pl/sql table;

2º Criar uma trigger before insert/update/delete a nível de instrução sobre a tabela, e nesta trigger limpar a table da package.

3º Criar uma trigger afeter insert/update/delete a nível de linha sobre a tabela, adicionando na table da package as chaves/rowid das linhas que acabaram de ser incluídas.

4º Criar uma trigger after insert/update/delete a nível de instrução sobre a tabela, na qual você irá percorrer a table da package e realizar as ações necessárias sobre as linhas inseridas.

Qualquer coisa, procure sobre o erro ORA-04091 (table ... is mutating, trigger/function may not see it) que você podesrá encontrar alguns exemplos.
GilberttJR
Rank: Estagiário Sênior
Rank: Estagiário Sênior
Mensagens: 8
Registrado em: Sex, 26 Out 2007 9:33 am
Localização: São Paulo

Bom...

Uma parte do problema está ok. Ou seja eu consigo pegar os registros da tabela na qual realizei o insert.

mas eu ainda preciso capturar os dados que acabei de inserir nesta tabela para usá-los dentro desta trigger.

vou colocar , a seguir uma serie de códigos que testei aqui e quero mostrar como um exemplo do que eu quero fazer.

Não atentem para a "regra de negócio", já que ela é um tanto quanto esquisita neste exemplo. Mas atente para o que realmente estou tentando fazer, ou seja recuperar a informação que foi inserida momentos antes da trigger ser chamada.

ESTOU CRIANDO TRES TABELAS PARA ESTA TESTE

Selecionar tudo

create table TESTE(
    ID   NUMBER,
    NOME VARCHAR2(100),
    NOMEDOCHEFE VARCHAR2(100) 
  ); 
  
create table FUNC(
    ID   NUMBER,
    NOME VARCHAR2(100) 
  ); 
  
create table QTDE_CHEFES(
    NOME VARCHAR2(100),
    CHEFES VARCHAR2(100)
  ); 
  


-- VOU PRECISAR POPULAR UMAS DELAS, OU SEJA, A DE FUNCIONARIOS

Selecionar tudo

  

INSERT INTO FUNC VALUES (1,'JOAO');
INSERT INTO FUNC VALUES (2,'MARIA');
INSERT INTO FUNC VALUES (3,'LUDOVICO');
COMMIT;


-- AQUI UM SELECT APENAS DE CONFIRMAÇÃO

Selecionar tudo

  

select * from FUNC;



-- MODIFIQUEI UM POUCO A TRIGGER QUE ME FOI ENVIADA PELO TREVISOLLI

Selecionar tudo

CREATE OR REPLACE TRIGGER TRG_TESTE_01 
 AFTER 
 INSERT 
 ON TESTE 
 REFERENCING OLD AS OLD NEW AS NEW 
DECLARE 
   V_QTDE NUMBER(10); -- NESTA VARIAVEL VOU COLOCAR A QUANTIDADE DE CHEFES DE UM FUNCIONARIO 
BEGIN 
   SELECT COUNT(NOME) INTO V_QTDE FROM TESTE where NOME = NOME_QUE_EU_INSERI_MOMENTOS_ANTES_DESTA_TRIGGER; 
   --NOME_QUE_EU_INSERI_MOMENTOS_ANTES_DESTA_TRIGGER seria UMA VARIÁVEL  que guardasse todos 
   --os nomes que forma inseridos num INSERT 
   -- experimento trocar a variavel NOME_QUE_EU_INSERI_MOMENTOS_ANTES_DESTA_TRIGGER  pela string 
   -- 'MARIA' , por exemplo para entender o que eu quero fazer.
   
   INSERT INTO QTDE_CHEFES VALUES (NOME_QUE_EU_INSERI_MOMENTOS_ANTES_DESTA_TRIGGER, 'TEM '||V_QTDE||' CHEFES') ;
   -- A MINHA INTENÇÃO É COLOCAR ESTAS DUAS LINHAS NUM LOOP PARA QUE SEJAM INSERIDAS , NA  TABELA
   -- QTDE_CHEFES TODAS AS LINHAS CORRESPONDENTES A CADA NOME QUE FOI INSERIDO NA TABELA TESTE
EXCEPTION 
 WHEN OTHERS THEN 
     RAISE_APPLICATION_ERROR(-20001, 'Erro Trigger: ' || SQLERRM  ); 
END; 
/ 





-- AQUI UM TESTE DE INSERT , ONDE SERÃO ADICIONADAS VARIAS LINHAS NA TABELA TESTE NUM UNICO "INSERT"

Selecionar tudo

  

insert into TESTE (ID, NOME, NOMEDOCHEFE) 
           select 1, NOME,'CHEFE 3'
           from FUNC where 
           NOME in ('JOAO','MARIA','LUDOVICO');
COMMIT;           



-- APÓS REALIZAR O INSERT ACIMA , A TABELA QTDE_CHEFES DEVE MOSTRAR A FRASE "TEM X CHEFES" NA COLUNA CHEFES

Selecionar tudo

  
select * from QTDE_CHEFES;

select * from teste ;



Concluindo, eu preciso , após o insert de todos os dados serem realizados, capturar cada informação inserida em cada campo para usá-la dentro da trigger.

mais uma vez , obrigado pela atençao
Trevisolli
Moderador
Moderador
Mensagens: 2016
Registrado em: Qua, 12 Jan 2005 3:25 pm
Localização: Araraquara - SP
Abraço,

Trevisolli
OCA Oracle PL/SQL Developer Certified Associate
OCP Oracle Forms Developer Certified Professional
Araraquara-SP

Brother, no exemplo...

Essa quantidade de chefes que você tem que exibir, tem que ser, necessariamente após a inserção?

Não poderia estar em um botão, por exemplo, da tua aplicação ou, num outro momento, num processo?

A forma de se exibir essa informação tem que ser, necessariamente, após insert na tabela funcionário?
GilberttJR
Rank: Estagiário Sênior
Rank: Estagiário Sênior
Mensagens: 8
Registrado em: Sex, 26 Out 2007 9:33 am
Localização: São Paulo

Olá trevisolli.

Aqui estou eu de volta com a miinha "chatice". é é é.

Eu falei para não atentar para a regra do negócio :)

O exemplo que eu passei está bem distante da minha aplicação real. Na verdade não é minha e sim da empresa. Como existe aqui um certo cuidado em não ficar divulgando os códigos tenho que usar de "parábolas".

O que eu quero é trabalhar, dentro da trigger, com os registros que acabaram de ser inseridos antes de chamar a trigger e também poder usar a própria tabela que tem a trigger para fazer os devidos selects e tambem INSERTS quando necessário (isso mesmo que você pensou, pode haver recursão tambem).

Na verdade, trevisolli, o processo, o código da trigger e tudo mais já existe, porém para o bd do MSSQL server. Agora estou tentando fazer o mesmo para ORACLE pois vamos precisar trabalhar com o bd do ORACLE.

NO MSSQL server, a gente consegue recuperar , dentro da trigger, todos os dados que foram inseridos (seja uma linha ou mais num INSERT só).
Logo na seção de declaração criamos um cursor para armazenar na sua area de memoria um select de uma tal inserted, que imagino ser uma tabela temporaria do MSSQL server para guardar os valores que acabaram de ser inseridos.

Como já disse , no ORACLE, é possivel pegar tais valores quando trabalhamos com trigger de LINHA. Basta utilizar o :NEW.campo para pegar este valor. Porém a trigger é chamada para cada linha alterada, ou seja , o código que eu quero fazer, onde a própria tabela é mencionada num select, não pode ser executado. Dando o erro apontado pelo nosso colega rogenaro: "table ... is mutating, trigger/function may not see it"

OK, amigo ?
Trevisolli
Moderador
Moderador
Mensagens: 2016
Registrado em: Qua, 12 Jan 2005 3:25 pm
Localização: Araraquara - SP
Abraço,

Trevisolli
OCA Oracle PL/SQL Developer Certified Associate
OCP Oracle Forms Developer Certified Professional
Araraquara-SP

Então brother,

Sobre o Mutating, tem um exemplo bem legal do Dr_Gori, aqui no fórum:
http://www.glufke.net/oracle/viewtopic. ... t=mutating

Dá uma olhada nele e, se não lhe ajudar, a gente tenta outra forma, beleza?
Responder
  • Informação
  • Quem está online

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