避免使用触发器和 raise_application_error 将数据插入 table,而是将数据存储到日志 table
Avoid inserting data into a table using Trigger and raise_application_error, but store the data into a Log table
我需要检查产品销售是否已过期,将其日期与计算机的实际日期进行比较。如果产品过期,那么我无法将产品数据插入订单 Table,但我需要将它们插入日志 Table。
我可以避免使用 raise_application_error (-20001,'This product is not for sale anymore');
插入订单 Table。但是当我使用 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;
因为我的代码是葡萄牙语,所以我用英语写了一些评论
你需要在这里使用Autonomous Pragma
。它将确保父事务不会回滚子事务。
这是登录 sql 和 pl/sql.
的标准做法
请在此处查看示例:http://www.java2s.com/Tutorial/Oracle/0560__Trigger/Autonomoustriggers.htm
编辑:
我的建议是创建一个单独的 pl/sql proc,使用 Autonomous pragma 插入日志 table 并在需要时调用此 proc。这将确保日志语句不会回滚。
您可以使用 Autonomous Pragma
来记录您的数据,无论异常如何。基本上,您创建一个过程以插入日志 table。该过程的语法可以是:
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
我需要检查产品销售是否已过期,将其日期与计算机的实际日期进行比较。如果产品过期,那么我无法将产品数据插入订单 Table,但我需要将它们插入日志 Table。
我可以避免使用 raise_application_error (-20001,'This product is not for sale anymore');
插入订单 Table。但是当我使用 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;
因为我的代码是葡萄牙语,所以我用英语写了一些评论
你需要在这里使用Autonomous Pragma
。它将确保父事务不会回滚子事务。
这是登录 sql 和 pl/sql.
请在此处查看示例:http://www.java2s.com/Tutorial/Oracle/0560__Trigger/Autonomoustriggers.htm
编辑:
我的建议是创建一个单独的 pl/sql proc,使用 Autonomous pragma 插入日志 table 并在需要时调用此 proc。这将确保日志语句不会回滚。
您可以使用 Autonomous Pragma
来记录您的数据,无论异常如何。基本上,您创建一个过程以插入日志 table。该过程的语法可以是:
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