【问题标题】:Insert inside the trigger in oracle [duplicate]在oracle中插入触发器[重复]
【发布时间】:2017-08-10 21:56:44
【问题描述】:

我正在尝试为学生项目制作简单的触发器。它将在价格表上触发。

CREATE TABLE "STD_USER"."HT_PRICES" 
(   "PRC_ID" NUMBER, 
"PRC_DATE_FROM" DATE, 
"PRC_DATE_TO" DATE, 
"PRC_STD_ID" NUMBER, 
"PRC_AMOUNT" NUMBER
)

触发器的主要目标是检查任何预订是否没有对更新的价格行的任何引用。

如果任何行实际上对更新的行有引用,我们需要将新价格插入到价格表中,开始日期 (PRC_DATE_FROM) 等于上次预订的结束时间。 触发器主体:

create or replace 
TRIGGER "TRG_NEW_PRICE" BEFORE UPDATE ON HT_PRICES 
REFERENCING OLD AS old NEW AS new 
FOR EACH ROW
DECLARE
  v_last_rsv_date DATE;
  v_temp_date_to DATE;
  v_std_id NUMBER;
  v_amount NUMBER;
BEGIN
  BEGIN
    SELECT MAX(RSV_DATE_TO) 
    INTO v_last_rsv_date 
    FROM HT_RESERVATION, 
       HT_ROOMS, 
       HT_STANDARDS, 
       HT_PRICES
    WHERE RSV_ROM_ID=ROM_ID 
    AND ROM_STD_ID=STD_ID 
    AND STD_ID=:new.PRC_STD_ID;

    EXCEPTION
      WHEN NO_DATA_FOUND THEN 
      RETURN;
  END;
  --do skrocenia starej ceny
  v_temp_date_to:= :new.PRC_DATE_TO;
  --poprawna data dla nowej ceny to v_last_rsv_date
  :new.PRC_DATE_TO:= v_last_rsv_date;
  v_amount:=:new.PRC_AMOUNT;
  :new.PRC_AMOUNT:=:old.PRC_AMOUNT;
  v_std_id:=:new.PRC_STD_ID;
  :new.PRC_STD_ID:=:old.PRC_STD_ID;
  COMMIT;
  --skrocenie starej ceny w nowym rekordzie cenowym
  HP_MANAGING.ADD_PRICE(v_last_rsv_date, v_temp_date_to, v_std_id, v_amount);

END;

任何想法如何解决它?当我尝试对其进行测试时,我得到了日志:

从命令的第 10 行开始出错:
更新 HT_PRICES SET PRC_AMOUNT=501 其中 prc_id=1
错误报告:
SQL 错误:ORA-04091:表 STD_USER.HT_PRICES 正在变异,触发器/函数可能看不到它 ORA-06512:在“STD_USER.TRG_NEW_PRICE”,第 8 行
ORA-04088: 执行触发器“STD_USER.TRG_NEW_PRICE”时出错
04091. 00000 - “表 %s.%s 正在变异,触发器/函数可能看不到它”
*原因:触发器(或用户定义的 plsql 函数,在 这个语句)试图查看(或修改)一个表 正在被触发它的语句修改。
*操作:重写触发器(或函数),使其不读取该表。

【问题讨论】:

  • 首先,您永远不应该在触发器中进行提交。坏的。如果 HP_MANAGING.ADD_PRICE 正在更新触发器所在的同一个表,那就有问题了。
  • 为什么触发器内的查询(错误文本中的第 8 行)在 where 子句中包含 HT_PRICES - 它真的需要再次查看该表,而不仅仅是 @987654325 @伪记录?使用适当的现代连接语法,查询会更容易理解,并且每个列引用都以它来自的表(或该表的别名)为前缀。再加上 OldProgrammer 所说的……

标签: oracle oracle11g triggers


【解决方案1】:

1) 将您的 SELECT 放入标有 pragma autonomous_transaction 的本地过程中,这将允许 select 运行,但您不会看到当前事务未提交的更改。

2) COMMIT;BEFORE DML 触发器中的原因是什么?

【讨论】:

  • 我可能弄错了,但可以肯定autonomous_transaction 与选择无关。
  • 它会停止抛出变异表错误,但这是一个糟糕的解决方案 - 正如你所说的那样,它不会看到当前事务,并且通常是避免此错误的糟糕技巧。很少需要自主交易。
  • autonomous_transaction 隐藏当前事务未提交的更改,就像SELECT 在不同的会话中运行一样。
猜你喜欢
  • 1970-01-01
  • 2018-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-16
  • 2018-04-11
  • 2021-08-25
  • 2014-06-28
相关资源
最近更新 更多