Wab*_*bit 0 oracle triggers plsql
在插入乘客表后尝试触发触发器时,我会收到此错误。此触发器应该调用一个过程,该过程采用新插入值的两个参数,并基于此更新另一个表,即预订表。但是,我收到此错误:
ORA-04091: table AIRLINESYSTEM.PASSENGER is mutating, trigger/function may not see it
ORA-06512: at "AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE", line 11 ORA-06512: at
"AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE", line 15 ORA-06512: at
"AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE_T1", line 3 ORA-04088: error during execution of
trigger 'AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE_T1' (Row 3)
Run Code Online (Sandbox Code Playgroud)
我在 SQL 命令行中编译并测试了该过程,它工作正常。问题似乎出在触发器上。这是触发代码:
create or replace trigger "CALCULATE_FLIGHT_PRICE_T1"
AFTER
insert on "PASSENGER"
for each row
begin
CALCULATE_FLIGHT_PRICE(:NEW.BOOKING_ID);
end;?????
Run Code Online (Sandbox Code Playgroud)
为什么触发器不调用过程?
您正在以不应该使用的方式使用数据库触发器。数据库触发器尝试读取它当前正在修改的表。如果 Oracle 允许您这样做,您将执行脏读。幸运的是,Oracle 会警告您的行为,您可以修改您的设计。
最好的解决方案是创建一个 API。一个程序,最好是在一个包裹中,允许您以您想要的方式插入乘客。在伪 PL/SQL 代码中:
procedure insert_passenger
( p_passenger_nr in number
, p_passenger_name in varchar2
, ...
, p_booking_id in number
, p_dob in number
)
is
begin
insert into passenger (...)
values
( p_passenger_nr
, p_passenger_name
, ...
, p_booking_id
, p_dob
);
calculate_flight_price
( p_booking_id
, p_dob
);
end insert_passenger;
/
Run Code Online (Sandbox Code Playgroud)
您现在将调用此过程,而不是插入语句。你的变异表问题将消失。
如果您坚持使用数据库触发器,则需要避免游标 c_passengers 中的 select 语句。这没有任何意义:您刚刚在表乘客中插入了一行并知道所有列值。然后您调用calculate_flight_price 来检索您已经知道的列DOB。只需在您的 calculate_flight_price 过程中添加一个参数 P_DOB 并使用 :new.dob 调用它,如下所示:
create or replace trigger calculate_flight_price_t1
after insert on passenger
for each row
begin
calculate_flight_price
( :new.booking_id
, :new.dob
);
end;
Run Code Online (Sandbox Code Playgroud)