Ir para conteúdo
Fórum Script Brasil
  • 0

(Resolvido) Erro de violação de chave primaria


pestana.

Pergunta

Boa tarde!

Alguma coisa tem de errado neste código eu suspeito que seja esta trigger no bloco For Select ... Into Do, se eu retirar este bloco funciona mas logicamente somente se houver um item por pedido, quando eu adiciono este bloco For Select ... Into Do o erro acontece...

Invalid insert or update value(s): object columns are
constrained - no 2 table rows can have duplicate column values.
violation of PRIMARY or UNIQUE KEY constraint "PK_SALDOESTOQUE" on table "SALDO_ESTOQUE".
Problematic key value is ("ID_MOVIMENTO" = 62, "ID_PRODUTO" = 1, "ID_EMBALAGEM" = 1).
At procedure 'ADD_SALDO_ESTOQUE' line: 15, col: 4
At procedure 'REAJUSTAR_SALDOESTQ' line: 41, col: 8
At trigger 'ADICIONAR_ESTOQUE' line: 34, col: 11.

alguém poderia me dar um Help?


Explicação do código:

Existe as tabelas de pedido_entrada, item_entrada, movimento_estoque e saldo_estoque.
pedido_entrada e item_entrada: armazena os pedidos de compra.
movimento_estoque e saldo_estoque: armazena as movimentações e seu saldo de estoque, respectivamente.

Esta Trigger é disparado depois de atualizar a tabela pedido_entrada (pedido de compra) aonde o campo status for alterado de (P)endente para (F)inalizado.
A inteção é adicionar todos os itens do pedido de compra na tabela saldo de estoque (não esquecendo que a estrutura é um mestre-detalhe movimento_estoque 1-N saldo_estoque).

 

set term ^ ;

create trigger adicionar_estoque for pedido_entrada
active after update position 0
as
   declare variable idMovimento integer;
   declare variable idProduto integer;
   declare variable idEmbalagem integer;
   declare variable valorCusto numeric(13,2);
   declare variable margem numeric(7,2);
   declare variable valorVenda numeric(13,2);
   declare variable percDesc numeric(5,2);
   declare variable qtdeItem numeric(10,3);
   declare variable qtdeEstq numeric(13,3);
   declare variable valorTotal numeric(18,2);
begin      /* se o status do pedido estiver como finalizado */
   if ((old.status = 'P') and (new.status = 'F')) then
    begin  /* inclui registro na tabela movimento_estoque */
       execute procedure add_movimento_estoque(old.id_pedido,NULL,2,NULL,'N')
       returning_values :idMovimento;
       /* retorna o último saldo de estoque em que o código do produro e embalagem seja igual ao do item do pedido */
       for select s.id_produto, s.id_embalagem, i.valorUnitario, s.percentual,
                  s.valorVenda, s.percentDesc, s.qtdeAtual, i.quantidade, s.valorTotal
           from item_entrada i
                inner join saldo_estoque s on(i.id_produto = s.id_produto and
                                              i.id_embalagem = s.id_embalagem)
           where (i.id_pedido = old.id_pedido)
           and (s.id_movimento = (select max(id_movimento)
                                  from saldo_estoque
                                  where (id_produto = s.id_produto)
                                  and (id_embalagem = s.id_embalagem)))
           into :idProduto, :idEmbalagem, :valorCusto, :margem, :valorVenda, :percDesc, 
                :qtdeEstq, :qtdeItem, :valorTotal
       do
       begin
          execute procedure reajustar_saldoEstq('E',2,:idMovimento,:idProduto,:idEmbalagem,
                                                :qtdeItem,:qtdeEstq,:valorCusto,:margem,
                                                :valorVenda,:percDesc,:valorTotal); 
       end
    end
end ^

set term ; ^


set term ^ ;

create procedure reajustar_saldoEstq(
operacao char(1) character set win1252,
idTipo integer,
idMovimento integer,
idProduto integer,
idEmbalagem integer,
qtde numeric(10,3),
qtdeEstq numeric(13,3),
valorCusto numeric(13,2),
margem numeric(7,2),
valorVenda numeric(13,2),
percDesc numeric(5,2),
valorTotal numeric(18,2))
as
   declare variable custoMedio numeric(13,2);
   declare variable valorMov numeric(15,2);
begin  /* reajusta a quantidade em estoque e o valor total de custo. */
   if (operacao in ('E','S','I')) then
    begin
       if (operacao = 'E') then     /* entrada.    */
        begin
           qtdeEstq = (:qtdeEstq + :qtde);
           valorMov = (:valorCusto * :qtde);
           valorTotal = (:valorTotal + :valorMov);
        end
       else
       if (operacao = 'S') then     /* saída.      */
        begin
           qtdeEstq = (:qtdeEstq - :qtde);
           valorMov = (:valorCusto * :qtde);
           valorTotal = (:valorTotal - :valorMov);
        end
       else
       if (operacao = 'I') then     /* inicializa. */
        begin
           qtdeEstq = :qtde;
           valorMov = (:valorCusto * :qtde);
           valorTotal = :valorMov;
        end
       /* inclui registro na tabela saldo_estoque. */
       execute procedure add_saldo_estoque (:idMovimento,:idProduto,:idEmbalagem,
                                            :valorCusto,:margem,:valorVenda,:percDesc,
                                            :qtde,:valorMov,:qtdeEstq,:valorTotal);
       /* idTipo 2: entrada por compra, 4: devolução de venda, 5: devolução de compra                                */
       /* devolução de ... para casos em que o valor de custo da "devolução" seja diferente do valor de custo atual. */
       if ((operacao in ('E','S')) and (idTipo in (2,4,5))) then
        begin  /* se o custo médio for alterado, recalcula o custo e inclui um novo movimento. */
           custoMedio = (:valorTotal / :qtdeEstq);
           if (:valorCusto <> :custoMedio) then
            begin
               execute procedure add_movimento_estoque (NULL,NULL,1,NULL,'N')
               returning_values :idMovimento;
               execute procedure add_saldo_estoque (:idMovimento,:idProduto,:idEmbalagem,
                                                    :custoMedio,:margem,:valorVenda,:percDesc,
                                                    0,0,:qtdeEstq,:valorTotal);
            end
        end
    end
end ^

set term ; ^

 

Obrigado!

 

Link para o comentário
Compartilhar em outros sites

9 respostass a esta questão

Posts Recomendados

  • 0

 

Iválido Inserir ou atualizar valor (es): as colunas de objeto são Restringidos - nenhuma linha de tabela 2 pode ter valores de coluna duplicados.

Violação da restrição PRIMARY ou UNIQUE KEY "PK_SALDOESTOQUE" na tabela "SALDO_ESTOQUE".

O valor chave problemático é ("ID_MOVIMENTO" = 62, "ID_PRODUTO" = 1, "ID_EMBALAGEM" = 1).

No procedimento 'ADD_SALDO_ESTOQUE' linha: 15, col: 4

No procedimento 'REAJUSTAR_SALDOESTQ' linha: 41, col: 8

No gatilho 'ADICIONAR_ESTOQUE' linha: 34, col: 11.

 

OBS: dentro do For voce não pode repetir valores para chave primaria ou chave unica para SALDOESTOQUE na tabela SALDO_ESTOQUE, caso contrário voce deve tirar a chave

Abraço

Link para o comentário
Compartilhar em outros sites

  • 0

Bom dia meu amigo!

Se eu executar o select no banco o resultado é:

id_produto = 1 | id_embalagem = 1 | valorUnitario = 25 | percentual = 0 | valorVenda = 0 | percentDesc = 0 | qtdeAtual = 14 | quantidade = 2 | valorTotal = 325

id_produto = 2 | id_embalagem = 1 | valorUnitario = 75 | percentual = 0 | valorVenda = 0 | percentDesc = 0 | qtdeAtual = 3 | quantidade = 3 | valorTotal = 225

Repare que dentro do For Select ... não se repete, porque a chave no primeiro laço ficaria com:

id_movimento = 62, id_produto = 1, id_embalagem = 1 

depois na próximo iteração do loop seria:

id_movimento = 62, id_produto = 2, id_embalagem = 1 

Eu não consigo entender o porque desta mensagem!

 

Obrigado por esta me ajudando!

 

Editado por pestana.
correção
Link para o comentário
Compartilhar em outros sites

  • 0

veja novamente

O valor chave problemático é ("ID_MOVIMENTO" = 62, "ID_PRODUTO" = 1, "ID_EMBALAGEM" = 1).

procure verificar esses valores

 

Na procedure 'ADD_SALDO_ESTOQUE' linha: 15, coluna: 4

Na procedure 'REAJUSTAR_SALDOESTQ' linha: 41, coluna: 8

No trigger 'ADICIONAR_ESTOQUE' linha: 34, coluna: 11.

procure verificar o código ( pela linha e coluna onde ocorre o erro )

 

OBS: para tirar a dúvida, retire as chaves e teste ... se o erro não ocorrer voce já saberá onde está o problema

use o break point do dephi para depurar o código, e achar o erro

abraço

Link para o comentário
Compartilhar em outros sites

  • 0

Quando eu retirei a chave primaria composta pk_saldoEstoque aconteceu algo estranho... 

agora parece que entra num loop infinito e não consigo sair senão fazendo a finalização forçada.

Quando eu fui ver o gerador (generator) do campo campo id_movimento estava com 2559, de 62 foi pra este número.

Eu estou perdendo vários dias pra tentar encontrar aonde esta o erro mas tá difícil.

Meu amigo o que eu tenho que fazer agora?


Obrigado pela a sua paciência!
 

Link para o comentário
Compartilhar em outros sites

  • 0

vou te dar um dica, para casos como esse:

copie esse código em um bloco de notas e salve como texto

depois apague o código do programa

não use chaves e nem campos autoincremento na tabela

começe do zero novamente, mas vá testando partes do código separadamente

a cada sucesso, voce vai incrementando o código e testando

se no final, depois de todo o código ser implementado, funcionar, então voce coloca as chaves e testa.

Não adianta ficar batendo cabeça no código com erro

abraço

 

 

 

 

Link para o comentário
Compartilhar em outros sites

  • 0

Pessoal desconsidere os códigos acima e verifique esta Trigger. Fazendo os testes eu descobri que ao incluir registros na tabela "saldo_estoque" dentro do For Select Do ocorre este erro.

Parece que o loop For Select tenta incluir duas vezes o mesmo registro na tabela saldo_estoque, deem uma olhada na declaração select ...

SET TERM ^ ;

CREATE OR ALTER TRIGGER ADICIONAR_ESTOQUE FOR PEDIDO_ENTRADA
ACTIVE AFTER UPDATE POSITION 0
as
   declare variable idMovimento integer;
   declare variable idProduto integer;
   declare variable idEmbalagem integer;
   declare variable valorCusto numeric(13,2);
   declare variable margem numeric(7,2);
   declare variable valorVenda numeric(13,2);
   declare variable percDesc numeric(5,2);
   declare variable qtdeItem numeric(10,3);
   declare variable qtdeEstq numeric(13,3);
   declare variable valorTotal numeric(18,2);
begin      /* se o status do pedido estiver como finalizado */
   if ((old.status = 'P') and (new.status = 'F')) then
    begin  /* inclui registro na tabela movimento_estoque */
       execute procedure add_movimento_estoque (old.id_pedido,NULL,2,NULL,'N')
       returning_values :idMovimento;
       /* retorna o último saldo de estoque em que o código do produro e embalagem seja igual ao do item do pedido */
       for select s.id_produto, s.id_embalagem, i.valorUnitario, s.percentual,
                  s.valorVenda, s.percentDesc, s.qtdeAtual, i.quantidade, s.valorTotal
           from item_entrada i
                inner join saldo_estoque s on(i.id_produto = s.id_produto and
                                              i.id_embalagem = s.id_embalagem)
           where (i.id_pedido = old.id_pedido)
           and (s.id_movimento = (select max(id_movimento)
                                  from saldo_estoque
                                  where (id_produto = s.id_produto)
                                  and (id_embalagem = s.id_embalagem)))
           into :idProduto, :idEmbalagem, :valorCusto, :margem, :valorVenda, :percDesc, 
                :qtdeEstq, :qtdeItem, :valorTotal
       do
       begin
          insert into saldo_estoque (id_movimento, id_produto, id_embalagem, valorCusto,
                                     percentual, valorVenda, percentDesc, qtdeMov,
                                     valorMov, qtdeAtual, valorTotal)
          values (:idMovimento, :idProduto, :idEmbalagem, :valorCusto, :margem,
                  :valorVenda, :percDesc, 0, 0, :qtdeEstq, :valorTotal);
       end
    end
end ^

SET TERM ; ^

Agora estou tentando encontrar uma solução para este problema, quem puder me ajudar eu agradeço!


Obrigado!
 

Link para o comentário
Compartilhar em outros sites

  • 0

Meu amigo valeu pelas dicas e o empenho em querer me ajudar!

Eu consegui resolver refazendo o select em vez de um único select declarado no loop "For Select".

Agora eu não consegui entender o porque do erro que estava acontecendo?

de uma olhada neste fórum no qual um amigo me ajudou http://www.activedelphi.com.br/forum/viewtopic.php?t=92982

 

Obrigado!

Link para o comentário
Compartilhar em outros sites

  • 0
  for select i.id_produto, i.id_embalagem, i.valorUnitario, i.quantidade 
           from item_entrada i 
           where i.id_pedido = old.id_pedido 
           into :idProduto, :idEmbalagem, :valorCusto, :qtdeItem 
       do 
       begin 
           select first 1 s.percentual, s.valorVenda, s.percentDesc, s.qtdeAtual, s.valorTotal 
           from saldo_estoque s 
           where s.id_produto = :idProduto and 
                 s.id_embalagem = :idEmbalagem 
           order by s.id_movimento desc 
           into :margem, :valorVenda, :percDesc, :qtdeEstq, :valorTotal; 
            
           insert -- ... 
       end

Retirado do Forum Active Delphi ( Imex )

Veja que o seu 2º select depende de uma condição que está dentro do for da 1ª select

bem diferente da select que esta em seu programa

lembra do que falei no post anterior ?

começe do zero novamente, mas vá testando partes do código separadamente

os campos retornados da 1ª select é que vão ser passados como parametros para a 2ª select

Que bom que voce encontrou a solução.

abraço

Link para o comentário
Compartilhar em outros sites

  • 0

Jhonas foi melhor desmembrar o select que eu havia montado (como o Imex sugeriu).

A finalidade (inclusão na tabela) é a mesma mas teria que ser desmembrado em 2 selects para que eu pudesse incluir a linha retornada de cada iteração na tabela saldo_estoque, caso contrario, ocorreria erro de violação de chave por tentativa de incluir o mesmo registro que foi incluído anteriormente.

 

Muito obrigado pela ajuda!

Link para o comentário
Compartilhar em outros sites

Participe da discussão

Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152.1k
    • Posts
      651.8k
×
×
  • Criar Novo...