Ir para conteúdo
  • Cadastre-se

dev botao

Alterar Trigger Dentro De Outra Trigger


Ver Solução Respondido por carlessoflu,
  • Este tópico foi criado há 3649 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Recommended Posts

Postado

Tenho a seguinte situação: tenho uma tabela de estoque de produtos (ESTOQUE_PROD) e uma tabela de estoque de matéria-prima (ESTOQUE_MAT), preciso que ao atualizar qualquer uma das tabelas a outra tbm atualize, ex: ao atualizar o estoque de um produto atualize tbm o estoque da matéria-prima referente ao produto e vice versa.
Para isso criei uma trigger em cada tabela, quando atualizo a tabela ESTOQUE_PROD a trigger atualiza tbm a tabela ESTOQUE_MAT e vice versa, porém, isso faz com que o sistema fique em looping, um atualizando o outro sempre.
Tive a ideia de desabilitar a trigger antes de fazer o update e habilitar depois do update, porem o firebird não aceita a palava chave ALTER dentro da trigger.
Segue a trigger da tabela de ESTOQUE_PROD:
#Código

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TRIGGER ESTOQUE_ATU_MATP FOR ESTOQUE_PROD
ACTIVE AFTER UPDATE POSITION 0
AS
begin
   --desabilitar a trigger da tabela ESTOQUE_MAT para não entrar em looping
   alter trigger estoque_atu_prod inactive;
           
   --atualizar estoque de matéria-prima
   update ESTOQUE_MAT set quant = new.q1 where referencia = new.referencia;
            
   --habilitar a trigger da tabela materiapest
   alter trigger estoque_atu_prod active;
        
end
end


Alguém sabe o que devo fazer?

  • Moderadores
Postado (editado)

Tentou usar um campo flag? Por exemplo, quando a atualização for feita pela primeira vez, grave o flag para 2. Assim você executará a trigger somente se esse flag for < 2.

 

If Flag < 2

begin

   executa trigger

   update tabela estoque set flag = 2

   update tabela matéria prima set flag = 2

end;

Editado por Gr@c@
Postado

Tentou usar um campo flag? Por exemplo, quando a atualização for feita pela primeira vez, grave o flag para 2. Assim você executará a trigger somente se esse flag for < 2.

 

If Flag < 2

begin

   executa trigger

   update tabela estoque set flag = 2

   update tabela matéria prima set flag = 2

end;

Boa tarde Gr@c@, muito obrigado pela resposta, mas não entendi muito bem, poderia me explicar melhor por favor?

- o que é esse campo Flag?

- Esse campo Flag ficaria onde? nas tabelas de estoque ou na própria trigger?

 

Muito obrigado por enquanto!

  • Moderadores
Postado (editado)

Esse nome Flag é só um exemplo. Trata-se de um campo identificador, que fica nas tabelas. No meu caso eu uso um campo chamado IDTRIGGER . Então a trigger só é ativada se o campo IDTRIGGER for <> 9.

 

Vou te dar um exemplo simplificado: Tenho uma tabela TB_Cliente que contem um campo chamado IDTRIGGER do tipo int. Na tabela TB_Cliente executo uma trigger de update se (e somente se) o campo IDTRIGGER capturado for <> 9. Se for = 9 não continuo executando o restante da trigger. Caso contrário, executo o restante da trigger onde dou update na TB_Cliente nos campos que precisam ser atualizados e também no campo IDTRIGGER setanto ele para 9. Isso interrompe um possível loop.

 

Apesar que creio eu que você não deveria colocar esse tipo de atualização em trigger. Por que não deixa isso por conta do próprio aplicativo? Ou, mais corretamente, em uma procedure de atualização que poderá ser usada por mais de um formulário?

 

ALTER TRIGGER [dbo].[TU_CLIENTE] ON [dbo].[TB_Cliente]
FOR UPDATE
AS
DECLARE
@EMPRESA INT,
@SETOR INT,
@ROTA INT,
@SETOR_ANTERIOR INT,
@ROTA_ANTERIOR INT,
@DEL_IDTRIGGER INT,
@INS_IDTRIGGER INT
BEGIN
  -- VERIFICA SE VAI EXECUTAR A TRIGGER ATRAVÉS DO CAMPO IDTRIGGER DA TABELA (IDTRIGGER <> 9) --
  SELECT @DEL_IDTRIGGER  = ISNULL(DEL.IDTRIGGER,0) FROM DELETED DEL
  IF @DEL_IDTRIGGER = 9 RETURN --> sai da trigger
  SELECT @INS_IDTRIGGER = ISNULL(INS.IDTRIGGER,0) FROM INSERTED INS
  IF @INS_TIDTRIGGER = 9 RETURN --> sai da trigger
  --************************************************************************************--
 
  IF ( UPDATE(Setor) ) or ( UPDATE(Rota) )
    begin
      Declare    CursorCLIU CURSOR FOR
      Select     Empresa, Setor, Rota from DELETED
      Open       CursorCLIU
      While      (1=1)
      begin
        Fetch Next From CursorCLIU into @Empresa, @Setor, @Rota
        if (@@Fetch_Status <> 0) Break
        Update TB_Rota Set QtdeCliente = (Select count(codigo) from tb_cliente where Empresa = @Empresa and Setor = @Setor and Rota = @Rota), IDTRIGGER = 9
        where Empresa = @Empresa and Setor = @Setor and Codigo = @Rota
      end;
      Close      CursorCLIU
      Deallocate CursorCLIU
      Declare    CursorCLIU2 CURSOR FOR
      Select     Empresa, Setor, Rota from INSERTED
      Open       CursorCLIU2
      While      (1=1)
      begin
        Fetch Next From CursorCLIU2 into @Empresa, @Setor, @Rota
        if (@@Fetch_Status <> 0) Break
        Update TB_Rota Set QtdeCliente = (Select count(codigo) from tb_cliente where Empresa = @Empresa and Setor = @Setor and Rota = @Rota), IDTRIGGER = 9
        where Empresa = @Empresa and Setor = @Setor and Codigo = @Rota
      end;
      Close      CursorCLIU2
      Deallocate CursorCLIU2
    end;
END;

Editado por Gr@c@
  • Moderadores
Postado

Pessoal, caso alguém tenha uma idéia melhor, fique a vontade para postar aqui. Assim, quem sabe eu também aproveite a idéia e refaça meus projetos. :mrgreen:

  • Consultores
Postado

Apesar que creio eu que você não deveria colocar esse tipo de atualização em trigger. Por que não deixa isso por conta do próprio aplicativo? Ou, mais corretamente, em uma procedure de atualização que poderá ser usada por mais de um formulário?

 

Acho que seria uma melhor opção utilizar uma ou duas procedures para fazer as atualizações.

 

Sobre o flag, como a atualização é em vários registros, talvez fosse melhor uma flag utilizando as variáveis de contexto.

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Postado

Acho que seria uma melhor opção utilizar uma ou duas procedures para fazer as atualizações.

 

Sobre o flag, como a atualização é em vários registros, talvez fosse melhor uma flag utilizando as variáveis de contexto.

Fica meio inviável pq são várias telas que fazem entrada/saída do estoque, se for colocar para fazer em cada tela vai ficar muito trabalhoso, e ainda posso esquecer de colocar em alguma né.

  • Moderadores
Postado (editado)

Amigo tenta aí. Lembrando que os meus comandos são para SqlServer. No Firebird eu desconheço os comandos.

 

 

CREATE TRIGGER ESTOQUE_ATU_MATP FOR ESTOQUE_PROD

ACTIVE AFTER UPDATE POSITION 0

AS

DECLARE
@IDTRIGGER INT

 

Begin

SELECT @IDTRIGGER = ISNULL(IDTRIGGER,0) FROM INSERTED INS ---> não sei como vc captura o valor de um campo na trigger no caso do firebird porque eu trabalho com SqlServer, mas vc tem que pegar o conteúdo do campo IDTRIGGER da tabela que está sofrendo alteração e jogar na variável @IDTRIGGER

IF @IDTRIGGER = 9

RETURN  ----> para por aqui

ELSE

BEGIN 

---> AQUI DÁ UPDATE NA TABELA NOS CAMPOS QUE VOCÊ PRECISA E SETANDO O CAMPO IDTRIGGER = 9

END

end

 

 

 

+ ou - assim.

Editado por Gr@c@
  • Consultores
Postado

Fica meio inviável pq são várias telas que fazem entrada/saída do estoque, se for colocar para fazer em cada tela vai ficar muito trabalhoso, e ainda posso esquecer de colocar em alguma né.

Sim. Mas ficaria correto, leve, com menos uso do servidor e fácil de dar manutenção.

 

Fora isso, o que você está mencionando não tem muito sentido. Quando você altera o valor de estoque de uma matéria prima não necessariamente deveria alterar o valor do estoque do produto.

Mas se realmente quiser fazer do jeito proposto, utilize uma variável de contexto para verificar se a trigger já está sendo executada mais de uma vez.

  • Curtir 1

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
  • Moderadores
Postado

O que o Elton disse está correto. Não faz mesmo sentido atualizar estoque da matéria-prima do produto ao atualizar estoque do produto. Tanto matéria-prima como produto final deveriam ter seus estoques atualizados no ato de produção (ficha técnica). Cuidado com triggers. Elas ajudam em alguns casos, mas limitam em outros.

  • Solution
Postado

É que um cliente quer que o sistema funcione dessa forma para ele, por isso estou fazendo essa modificação.

 

Muito obrigado pela ajuda, consegui resolver pegando a base do que vcs me ajudaram.

 

Vou postar o código da trigger na tabela de estoque de matéria prima, caso alguém tbm tenha essa dúvida.

CREATE TRIGGER ESTOQUE_ATU_PROD FOR MATERIAPEST
ACTIVE AFTER UPDATE POSITION 0
AS
  declare ASSOCIADO varchar(15);
  declare DESCRICAO varchar(120);
  declare ASSOC_LOJA integer;
  declare ASSOC_COR integer;
  declare ATU integer;
begin
  --verificar se é para fazer ou não o código da trigger - se for 0 não faz se for 1 faz
  --essa verificação é feita para não entrar em looping, ex: atualiza estoque_prod ai a trigger atualiza o estoque_mat
  --e vice-versa e fica no looping
  Select atu from atu_estoque_pela_trigger into :ATU;
  if (coalesce(:atu,0) = 1) then
     begin
       --buscar dados da materia prima
       Select assoc_loja, assoc_cor, associado, descricao from cad_materia where referencia = new.referencia
       into :ASSOC_LOJA, :ASSOC_COR, :associado, :DESCRICAO;
       if ((:ASSOCIADO is not null) and (:ASSOCIADO <> '')) then
          begin
            --faz um update colocando o atu = 0 para não fazer o codigo da trigger na tabela de estoque (produtos)
            update atu_estoque_pela_trigger set atu = 0;
            --atualizar estoque do produto
            update estoque set q1 = new.quant, quant_total = new.quant where referencia = :ASSOCIADO and loja = :ASSOC_LOJA and cor = :ASSOC_COR;
            --faz um update colocando o atu = 1 para voltar ao normal
            update atu_estoque_pela_trigger set atu = 1;
            --inserir registro no kardex
            insert into kardex (data, referencia, descricao, operacao, QUANT, cor, loja, tam, registro) values (current_date, :ASSOCIADO, :DESCRICAO, 'Associação a matéria-prima', (new.quant-old.quant), :ASSOC_COR, :ASSOC_LOJA, 'U', GEN_ID(gen_kardex,1));
          end
     end
end
  • Este tópico foi criado há 3649 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.