避免使用Trigger和raise_application_error将数据插入表中,但将数据存储到Log表中

时间:2015-10-23 03:03:39

标签: oracle logging plsql triggers insert

我需要检查产品销售是否已过期,将其日期与计算机的实际日期进行比较。如果产品已过期,那么我无法将产品数据插入订单表,但我需要将它们插入到日志表中。 我可以避免使用raise_application_error (-20001,'This product is not for sale anymore');插入订单表。但是当我使用raise_application_error时,似乎raise_application_error还回滚了触发器内的命令INSERT INTO LogTable ...。有没有更好的方法来解决这个问题而不使用raise_application_error? 观察:我需要使用Trigger并且不能使用INSTEAD-OF

create or replace TRIGGER Insercao_DetalhesPedido
    AFTER INSERT ON DetalhesPedido
    REFERENCING new AS novo_DP
    FOR EACH ROW

  DECLARE
    dataPedido Pedido.DTPedido%TYPE;
    dataVenda Produto.DTFimVenda%TYPE;
    dtVenda_Expirou EXCEPTION;

  BEGIN
    -- get the date from the order(it is a SYSDATE)
    SELECT DTPedido INTO dataPedido
    FROM Pedido 
    WHERE Pedido.codigo = :novo_DP.codigoPedido;

    -- get the date from the product(when it will expire)
    SELECT DTFimVenda INTO dataVenda
    FROM Produto
    WHERE Produto.codigo = :novo_DP.codigoProduto;

    --has the product expired?
    IF dataVenda < dataPedido THEN 
    -- Insert INTO the log table saying that this product have expired
      INSERT INTO Log
      VALUES(:novo_DP.codigoPedido, :novo_DP.codigoProduto, cast(SYSDATE as timestamp), dataPedido, 
             'Insercao Falha. DTVenda('||dataVenda||') < DataPedido('||dataPedido||')');
      RAISE dtVenda_Expirou;
    ELSE
      -- Insert INTO the log table saying that the product was succesfully inserted
       INSERT INTO Log
       VALUES(:novo_DP.codigoPedido, :novo_DP.codigoProduto, cast(SYSDATE as timestamp), dataPedido, 
             'Inserção De Produto em DetalhesPedido com sucesso');
    END IF;  

  EXCEPTION
  -- Product expired
  WHEN dtVenda_Expirou THEN
      raise_application_error (-20001,'A DATA DE VENDA DO PRODUTO EXPIROU');
  -- Order number not found
  WHEN NO_DATA_FOUND THEN
    raise_application_error (-20001,'NUMERO DO PEDIDO NÃO EXISTE');

END Insercao_DetalhesPedido;

我用英语写了一些评论,因为我的代码是葡萄牙语

2 个答案:

答案 0 :(得分:1)

您需要在此处使用Autonomous Pragma。它将确保父事务不会回滚子事务。 这是登录sql和pl / sql的标准做法。

请在此处查看示例:http://www.java2s.com/Tutorial/Oracle/0560__Trigger/Autonomoustriggers.htm

编辑:

我的建议是使用Autonomous pragma创建一个单独的pl / sql proc,以便在日志表中插入并在需要的地方调用此proc。这将确保不回滚日志语句。

答案 1 :(得分:1)

无论例外如何,您都可以使用Autonomous Pragma来记录您的数据。基本上,您创建一个插入日志表的过程。该过程可以具有以下语法:

CREATE OR REPLACE PROCEDURE auto_log(your parameters) is
....
PRAGMA AUTONOMOUS TRANSACTION;   --This statement makes the procedure autonomous
BEGIN
--your insert into log statement
COMMIT;
EXCEPTION WHEN OTHERS THEN
ROLLBACK;
END;
/

你的触发器将是:

....
--has the product expired?
IF dataVenda < dataPedido THEN 
-- Insert INTO the log table saying that this product have expired
   auto_log(your parameters)  --- call the procedure
   RAISE dtVenda_Expirou;
ELSE
  -- Insert INTO the log table saying that the product was succesfully inserted
  auto_log(your parameters)  --- call the procedure
END IF;  

EXCEPTION
-- Product expired
WHEN dtVenda_Expirou THEN
    raise_application_error (-20001,'A DATA DE VENDA DO PRODUTO EXPIROU');
-- Order number not found
WHEN NO_DATA_FOUND THEN
  raise_application_error (-20001,'NUMERO DO PEDIDO NÃO EXISTE');

END Insercao_DetalhesPedido;

请参阅here