Array
(
)

Dúvida em SP

Luiz Bertolazzi
   - 23 abr 2010

Estou com uma dúvida na SP abaixo a qual atualiza a quantidade na tabela Produto e inclui um registo na tabela MovEstoque.
Por exemplo, se houver duas transações, A e B, ao mesmo tempo para atualizar o mesmo produto.
- vamos considerar que a transação A inicia antes que a B.
- a transação A lê a qtd de produto para a variável xQtd, e a transação B também, digamos xQtd = 100 (parte 1 do código).
- a transação A atualiza a qtd de produto (parte 2 do código) e inclui um registro na tabela MovEstoque (parte 3) com as quantidades anterior e atual de produto.
- neste momento a transação B fica aguardando a finalização da transação A.
- a transação A executa um commit.
- a transação B atualiza a tabela Produto.
- a transação B incui um registro na tabela MovEstoque. Entretanto o conteúdo da variável xQtd está errado, pois houve uma alteração na tabela Produto feita pela transação A, então, o campo QuantAnterior da tabela MovEstoque terá um valor incorreto.

Gostaria de saber se a análise do código está certa e como posso resolver o problema do valor que é passado para a variável xQtd, pois na tabela MovEstoque preciso ter nos campos QuantAnterior e QuantAtual as quantidades do produto anterior e atual.



CREATE OR ALTER PROCEDURE CONTROLA_ESTOQUE (
    p_CodProd integer,
    p_Quant numeric(9,4))
as
   declare variable xQtd Numeri(9,4);

begin

   /* parte 1 - obtém a quantidade do produto que será a qtd anterior do movimento no estoque */
   Select QuantEstoque
   From Produto
   Where Codigo = :p_CodProd
   Into :xQtd;

   /* parte 2 - atualiza a qtd de produtos */
   Update Produto
   Set QuantEstoque = QuantEstoque + (:p_Quant)
   Where Codigo = :p_CodProd;

   /* parte 3 - incluir um movimento no estoque */
   Insert Into MovEstoque
   (Id,
    Data,
    CodProduto,
    QuantAnterior,
    QuantAtual)
   values
   (gen_id(Gen_MovEstoque, 1),
    current_date,
    :p_CodProd,
    :xQtd,
    (:xQtd + :p_Quant));

end


Emerson
   - 23 abr 2010

sinceramente, nunca vi guardar a quantidade anterior e atual num registro. não faz sentido e não é recomendável.
imagine que um registro de movimentação seja excluído. todos os valores das colunas daquele registro "pra baixo" deverão ser recalculados.

o correto é que esses valores sejam apurados em tempo real.

e outra coisa: para casos como esse, NUNCA guarde valores em variáveis.


de qualquer forma, tente algo assim:

CREATE OR ALTER PROCEDURE CONTROLA_ESTOQUE (
    p_CodProd integer,
    p_Quant numeric(9,4))
begin
   /* parte 1 - incluir um movimento no estoque */
   Insert Into MovEstoque
     (Id, Data, CodProduto, QuantAnterior, QuantAtual)
   select
     gen_id(Gen_MovEstoque, 1),
     current_date,
     Codigo,
     QuantEstoque,
     (QuantEstoque + :p_Quant)
   from
     Produto
   where
     Codigo = :p_CodProd;

   /* parte 2 - atualiza a qtd de produtos */
   Update Produto Set
     QuantEstoque = (QuantEstoque + :p_Quant)
   Where
     Codigo = :p_CodProd;
end

0
|
0