Trigger para "triplicar" registros ao serem inseri

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
jks1903
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 188
Registrado em: Qui, 04 Fev 2010 8:08 am

Pessoal, parece loucura mas devido a estrutra das tabelas existentes no nosso sistema preciso fazer uma gambiarra assim:

Tenho a tabela funcionarios, onde nessa tabela existe um campo chamado cd_empresa, que identifica a empresa onde o funcionário trabalha.

Possuimos apenas mais de uma razão social, mas a estrutura em si é uma só.
Então para cadastrarmos um funcionário novo o pessoal hoje está cadastrando ele em uma empresa e depois cadastrando o mesmo nas outras duas (são 3 empresas ao todo), pois são feitas configurações diferentes para cada funcionário e por isso não pode ser um cadastro único. Porém como são muitos campos a serem preenchidos esse processo está custando muito tempo.

O que quero é que, ao inserir um novo funcionário (sempre será inserido na empresa 1), essa trigger replique o cadastro copiando esse registro, mudanod apenas a chave primaria (cd_funcionario que é uma sequence) e o campo cd_empresa, para 2 e 3 respectivamente.

To quebrando a cabeça, hehe pois já tentei uma trigger que atualiza a propria tabela, porem me retorna um erro de tabela mutante....

Se alguém tiver uma idéia de que rumo devo tomar....
Obrigado desde já
victorhugomuniz
Moderador
Moderador
Mensagens: 1396
Registrado em: Sex, 01 Fev 2008 2:06 pm
Localização: Rio de Janeiro - RJ
Contato:
:D

vê se ajuda ..

você ta fazendo um select na tabela da trigger?
jks1903
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 188
Registrado em: Qui, 04 Fev 2010 8:08 am

Sim, na trigger eu tento né, rsrs , fazer um select na tabela onde o registro está sendo inserido, porém ele me retorna erro de tabela mutante.

Possivelmente, se não certamente, pelo fato da table estar sendo alterada e a trigger não ter a visao completa da tabela.

Meu problema é como sair disso, rsrs.

Vlw.
victorhugomuniz
Moderador
Moderador
Mensagens: 1396
Registrado em: Sex, 01 Fev 2008 2:06 pm
Localização: Rio de Janeiro - RJ
Contato:
:D

a minha pergunta era..

qual dado você precisa buscar via select na tabela?

você não teria esses dados atraves das proprias variaveis da trigger
:NEW ou :OLD ?
jks1903
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 188
Registrado em: Qui, 04 Fev 2010 8:08 am

a minha pergunta era..

qual dado você precisa buscar via select na tabela?

você não teria esses dados atraves das proprias variaveis da trigger
:NEW ou :OLD ?
Como eu preciso duplicar o registro, eu estou pegando todos os campos.

Selecionar tudo

select * from funcionario where cd_func = :new.cd_func
Estou tentando utilizar o :new, mas ele me dá erro de tabela mutante na linha que tem o select acima.

Estou empacado nessa parte. Depois que eu conseguir selecionar, eu farei um cursor ou algo parecido para inserir na tabbela esses dados, mudando apenas a cahve primaria onde incrementarei a sequence e informando a empresa, 2 e em seguida 3 no outro registro.
victorhugomuniz
Moderador
Moderador
Mensagens: 1396
Registrado em: Sex, 01 Fev 2008 2:06 pm
Localização: Rio de Janeiro - RJ
Contato:
:D

você não tem todos os campos atraves do :NEW ??

dai você não vai precisar do select e então seu insert vai dar certo sem erro mutante

não é simples assim?

:mrgreen:
jks1903
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 188
Registrado em: Qui, 04 Fev 2010 8:08 am

você não tem todos os campos atraves do :NEW ??

dai você não vai precisar do select e então seu insert vai dar certo sem erro mutante

não é simples assim?
Deixa ver se entendi.
Você está sugerindo que eu insira os dados na tabela utilizando somente o :new?
Tipo assim:

insert into funcionario
values(:new.campo1, :new.campo2, :new.campo3, ....) ??

Isso?
jks1903
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 188
Registrado em: Qui, 04 Fev 2010 8:08 am

Cara, testei daquela forma ali que postei acima e não obtive sucesso.

Persiste o erro da tabela mutante, agora na linha da inserção.

Acredito que isso deva acontecer porque minha trigger é for each row.

Porém se não for assim eu não tenho mais o :new e :old certo?

Ou eu posso obter os valores de :new e :old sem que a trigger seja for each row?
victorhugomuniz
Moderador
Moderador
Mensagens: 1396
Registrado em: Sex, 01 Fev 2008 2:06 pm
Localização: Rio de Janeiro - RJ
Contato:
:D

sim..
não funciona?
victorhugomuniz
Moderador
Moderador
Mensagens: 1396
Registrado em: Sex, 01 Fev 2008 2:06 pm
Localização: Rio de Janeiro - RJ
Contato:
:D

tendi..

então você vai ter que partir para a solução de mudar a sua trigger para uma instead OF
jks1903
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 188
Registrado em: Qui, 04 Fev 2010 8:08 am

não sei como utilizar essas triggers instead of, até já vi mas não compreendi mutio bem a lógica delas?

Você por acaso teria um exemplo?
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

Triggers instead of são válidas apenas para views.

Como no exemplo do tópico que o Victor postou, você pode realizar isto da seguinte forma:

1) Criar uma package com uma plsqltable para armazenar as chaves dos registros que foram inseridos;

2) Criar uma trigger before insert na tabela, limpando a plsqltable (trigger before insert);

3) Criar uma outra trigger sobre a tabela, before insert *para cada linha*, adicionando na plsqltable a chave do registro atual (trigger before insert for each row)

4) Criar uma terceira trigger sobre a tabela, after insert, percorrendo a plsqltable, por fim executando o código de sua trigger atual para cada registro recuperado.


Dá uma olhada novamente no tópico, pois o exemplo que o fsitja postou lá (no 7º post do tópico) atende perfeitamente a sua situação.
jks1903
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 188
Registrado em: Qui, 04 Fev 2010 8:08 am

Bom dia, desculpe a demora, mas só hoje retomei isso, rsrs...

Estive vendo outros casos e achei mais simples criar uma tabela temporária na trigger.
Com isso terei duas triggers.

A triger for each row armazena o rowid da linha que foi inserida.

E a after statement insere nessa mesma tabela os dados onde o rowid = ao rowid salvo na temoraria.

Ao fim disso limpo a tabela temporária.

Mas vlw pela ajuda.

Abraço.
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Olá,

Não sei exatamente como você implementou, mas acho que pode dar erro se dois usuários de forma simultânea tentarem executar o processo, pois a tabela temporária vai estar sendo usada pelos dois ao mesmo tempo.
jks1903
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 188
Registrado em: Qui, 04 Fev 2010 8:08 am

fsitja, realmente não previ isso.

Funcionou até agora porque geralmente há apenas um usuário alterando a tabela.

O processo todo em si leva cerca de 0.1s, e não temos muitos usuarios na base, mas mesmo assim não é?, uma hora pode acontecer.

Há alguma forma de bloquear a tabela durante o processo?
de forma que não seja possivel realizar alterações na mesma enquanto esse processo de duplicação não for encerrado?

Vlw pela dica.
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Se seu ambiente possui pouca concorrência de usuários, não deve ser um problema "serializar" o acesso à tabela, usando um LOCK TABLE em modo exclusivo.

Nesse caso, o primeiro usuário que chegar (mesmo que seja por 0.000001 seg) bloqueia a tabela, e o próximo é forçado a esperar pelo commit ou rollback dele para utilizá-la. Nesse caso você faria o commit apenas após limpar a tabela temporária. A intenção é que o segundo usuário não leia a "sujeira" do primeiro usuário e acabe replicando dados que não são seus.

Selecionar tudo

LOCK TABLE tab_temporaria IN EXCLUSIVE MODE;
http://download.oracle.com/docs/cd/E118 ... s_9015.htm
jks1903
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 188
Registrado em: Qui, 04 Fev 2010 8:08 am

Vlw, consegui.

Claro que por haver pouca concorrência não mudou nada aparentemente, mas com isso já será possivel eliminar esse erro.

Obrigado.
Marcelo Malta
Rank: Estagiário Sênior
Rank: Estagiário Sênior
Mensagens: 9
Registrado em: Ter, 28 Set 2010 3:23 pm
Localização: Serra-ES

Eu iria sugerir uma mudança um pouco mais radical. Já que cada funcionário precisará ser cadastrado nas 3 empresas. porque não criar uma nova tabela EMPRESA_FUNC, assim toda vez que cadastrar um funcionário na tabela funcionário, você só precisaria informar quais as empresas que este trabalhará. Hoje sua empresa tem 3 "filiais" e cada funcionário obrigatoriamente trabalha nas 3, mas se mudar a quantidade de empresas ou a obrigatoriedade de 3, você terá que alterar o trigger, dessa forma que estou sugerindo não.

Exemplificando.

EMPRESA -> EMPRESA_FUNC <- FUNC

um vinculo n para n.

Qualquer dúvida de como fazer isso, pode postar.

Abraços
jks1903
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 188
Registrado em: Qui, 04 Fev 2010 8:08 am

É que na verdade eu tenoh acesso somente ao banco de dados e não aos fontes do software.

Compramos esse software de gestao aqui para a empresa e para solicitarmos a troca, além de a diretoria achar caro o valor de implementação, é muito demorado o processo, até termos um retorno.

Ralmente essa seria a melhor opção, mas a estrutura atual do sitema não me permite isso.

MAs obrigado pela dica mesmo assim, vlw.
Responder
  • Informação
  • Quem está online

    Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante