【发布时间】: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 所说的……