:em02: 各位同仁高手请指教:表A有A_id,u_orig_value,parent_id等字段,parent_id指向表A的另一记录的A_id,
能否用表A的trigger实现---当A的某一条记录的字段u_orig_value发生变化时,相应修改其parent_id指向的记录的u_orig_value ??
我用过trigger,但资源锁定冲突啊!
小弟从网络搜索无所收获,从自己有的几本书也未能找到帮助,同事朋友给的建议就是尽量改用存储过程,存储过程需要调用者啊,而对用户来说多个按钮不知道做啥用的确不能少点不能多点,用户感到不理解。请求高手指教如何解决?不胜感谢!!!!
duwenhua 回复于:2004-06-09 18:05:13
是不是没有人能解决阿?
jrlee 回复于:2004-06-09 21:54:09
这样用trigger应该可以的,检查一下你的tigger是不是合理化的修改其相关记录
binary 回复于:2004-06-10 08:44:58
能否将你初步写的trigger贴上来,大家帮你看看
hyh1234 回复于:2004-06-10 09:29:23
可能是我反应太迟钝了,看不懂你想实现什么样的操作和你表中各字段的关系。
duwenhua 回复于:2004-06-10 11:05:51
谢谢各位大侠相助!!!感谢感谢先:)
是这样的:tablename-U_EQUIPMENT_Essence,包括如下字段:equipment_original_value、u_equipment_essence_id、u_main_equipment_essence_id。建的trigger如下:create or replace trigger U_EQUIPMENT_Essence_TRG
before update on U_EQUIPMENT_Essence
for each row
begin
update u_equipment_essence set equipment_original_value =equipment_original_value + :new.equipment_original_value where u_equipment_essence_id = :new.u_main_equipment_essence_id
and u_assembtype ='M';
end ;
报错如下:ORA-04091: 表 CQSBGL.U_EQUIPMENT_ESSENCE 发生了变化,触发器/函数不能读
ORA-06512: 在"CQSBGL.U_EQUIPMENT_ESSENCE_AFTER_TRG
请大家相助
duwenhua 回复于:2004-06-10 11:18:15
接上再说明一下,u_equipment_essence_id 为表u_equipment_essence的主键,u_main_equipment_essence_id用作关联的,u_assembtype 表示设备类别的,u_assembtype='M'表示主机 u_assembtype='P'表示部件,部件的u_main_equipment_essence_id字段存的就是主机的u_equipment_essence_id的值,当部件的equipment_original_value 增加或减少时,主机的也要相应增加或减少
在触发器中的本意是当部件的equipment_original_value 变化就修改其主机的equipment_original_value 。当前只锁定部件的记录行啊,为何修改主机会报 触发器/函数不能读 呢?
duwenhua 回复于:2004-06-10 11:32:52
我也试过用表层触发器,但表层是不能用:new或:old的阿,就是说我没办法找到当前修改的行,那么我只好写成如下:
Create Or Replace Trigger U_Equipment_Essence_After_Trg
after update
on u_equipment_essence
declare
cursor main_equipment is
select u_equipment_essence_id from u_equipment_essence
where u_assembtype ='M';
begin
for p1 in main_equipment loop
update u_equipment_essence es set
es.equipment_original_value = (select sum(equipment_original_value) from u_equipment_essence where u_main_equipment_essence_id =es.u_equipment_essence_id and u_assembtype='P'),
es.month_depreciation_value = (select sum(month_depreciation_value) from u_equipment_essence where u_main_equipment_essence_id =es.u_equipment_essence_id and u_assembtype='P'),
es.year_depreciation_value = (select sum(year_depreciation_value) from u_equipment_essence where u_main_equipment_essence_id =es.u_equipment_essence_id and u_assembtype='P'),
es.u_ljzj = (select sum(u_ljzj) from u_equipment_essence where u_main_equipment_essence_id =es.u_equipment_essence_id and u_assembtype='P')
where es.u_equipment_essence_id =p1.u_equipment_essence_id;
end loop;
end U_Equipment_Essence_After_Trg;
这样,运行时报错如下:ORA-00036: 超过递归 SQL (50) 级的最大值
ORA-06512: 在"CQSBGL.U_EQUIPMENT_ESSENCE_AFTER_TRG"
binary 回复于:2004-06-10 11:41:49
试试
.........
before update on U_EQUIPMENT_Essence
for each row
[color=red]
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
[/color]
begin
update u_equipment
..........
应该没有问题了
duwenhua 回复于:2004-06-10 11:42:39
如下的也报错:ORA-04091: 表 CQSBGL.U_EQUIPMENT_ESSENCE 发生了变化,触发器/函数不能读
create or replace trigger U_EQUIPMENT_Essence_TRG
before update
of equipment_original_value
on U_EQUIPMENT_Essence
for each row
when (new.u_assembtype ='P')
begin
update u_equipment_essence set
equipment_original_value =equipment_original_value + :new.equipment_original_value
where u_equipment_essence_id = :new.u_main_equipment_essence_id
and u_assembtype ='M';
end U_EQUIPMENT_Essence_TRG;
duwenhua 回复于:2004-06-10 11:47:40
按光明使者老兄的改了,如下:
create or replace trigger U_EQUIPMENT_Essence_TRG1
before update
on U_EQUIPMENT_Essence
for each row
declare
PRAGMA AUTONOMOUS_TRANSACTION;
begin
update u_equipment_essence set
equipment_original_value =equipment_original_value + :new.equipment_original_value
where u_equipment_essence_id = :new.u_main_equipment_essence_id
and u_assembtype ='M';
end U_EQUIPMENT_Essence_TRG1;
但还不行:ORA-00060: 等待资源时检测到死锁
ORA-06512: 在"CQSBGL.U_EQUIPMENT_ESSENCE_TRG1", line 4
duwenhua 回复于:2004-06-10 11:49:07
我变动了一下,如下:
create or replace trigger U_EQUIPMENT_Essence_TRG1
before update
of equipment_original_value
on U_EQUIPMENT_Essence
for each row
when (new.u_assembtype ='P')
declare
PRAGMA AUTONOMOUS_TRANSACTION;
begin
update u_equipment_essence set
equipment_original_value =equipment_original_value + :new.equipment_original_value
where u_equipment_essence_id = :new.u_main_equipment_essence_id
and u_assembtype ='M';
end U_EQUIPMENT_Essence_TRG1;
报错是:ORA-06519: 检测到活动的自治事务处理,已经回退
ORA-06512: 在"CQSBGL.U_EQUIPMENT_ESSENCE_TRG1", line 10
duwenhua 回复于:2004-06-10 12:09:18
请各位同仁高手发表各种看法见解啊,我是钻破头了啊!有哪位好心人提供专门讲解(oracle) trigger的资料、书籍也好,我去找办法。谢谢大家!
binary 回复于:2004-06-10 12:49:52
这种写法的trigger,需要commit,你再试试
追风篮人 回复于:2004-08-10 09:37:42
我也碰到了这个问题,请问这个问题最后解决了吗?
sidt 回复于:2004-08-10 14:55:29
建议对需要实现的业务再次分析,使之能够更便于实现。
对这种会接连触发的操作,一定要十分谨慎,否则避免触发器的更新操作再次触发了触发器的操作。在触发器中造成死循环。
追风篮人 回复于:2004-08-10 21:55:05
其实我个人觉得这个问题理论上应该可以解决。
对一个字段的UPDATE操作做触发器监视,触发器中在修改该字段的同时修改另一个触发器不做监视的字段,应该不会再次触发触发器,不会陷入死循环。
不知道是否会有这种比较直接的解决办法。
现在只好利用中间表记录修改情况,再借助后台存储过程的定时执行来更新源表的字段。。。
byheart 回复于:2004-08-11 18:09:36
You can do:
1. Rename your table with another name;
2. Create a view for select * from the table with the original name of the table;
3. Create a instead of trigger on the view, in the view you can access and update yur base table.
Example of instead of trigger for this case:
[ Code Start ]
create table t1(
id number(6) primary key
,pid number(6)
,value number(15,2)
,f1 varchar2(10)
,f2 varchar2(20)
);
create or replace view t1_v as select * from t1;
create or replace trigger bug_t1_v
instead of update on t1_v
for each row
declare
procedure update_parents(i_id in number, i_value in number);
procedure update_parents(i_id in number, i_value in number) is
begin
declare
l_pid t1.pid%type;
begin
select pid into l_pid
from t1
where id = i_id;
if l_pid <>; 0 then
update t1 set value = nvl(value,0) + nvl(i_value,0)
where id = l_pid;
update_parents(l_pid, i_value);
end if;
exception
when no_data_found then
null;
end;
end update_parents;
begin
--
-- Update Value Field for current record and Parent records
--
if nvl(:new.value,0) - nvl(:old.value,0) <>; 0 then
update t1 set value = value + nvl(:new.value,0) - nvl(:old.value,0)
where id = :new.id;
update_parents(:new.id, nvl(:new.value,0) - nvl(:old.value,0));
end if;
--
-- Update Others Fields
--
update t1 set f1 = :new.f1
,f2 = :new.f2
where id = :new.id;
end;
--
-- Testing
--
-- With this view: t1_v
--
begin
for i in 1..50 loop
Insert into t1_v values(i, i-1, 0, '', '');
end loop;
end;
/
delete from t1_v;
begin
for i in 1..50 loop
Insert into t1_v values(i, i-1, 0, '', '');
end loop;
end;
/
update t1_v set f1 = 'TEST' where id = 49;
update t1_v set value = value + 5 , f1 = 'AA', F2 = 'BB'
where id = 50;
[ Code End ]
追风篮人 回复于:2004-08-11 21:57:16
高手,GOOD IDEA!
这个主意不错,可以借鉴一下,明天去单位试试。
利用这个思想,稍微做一下改动。
源表因为是业务表,不宜做改动,触发器还是建在源表上为好,另外建一个同源视图,赋予它相应的UPDATE权限,在该触发器中再对视图做UPDATE操作更新视图的相应其它字段。。。
还不知道这种方法是否可行,明天试了再回复。。。
byheart 回复于:2004-08-12 12:47:26
引用:原帖由 "追风篮人" 发表: 高手,GOOD IDEA!
这个主意不错,可以借鉴一下,明天去单位试试。
利用这个思想,稍微做一下改动。
源表因为是业务表,不宜做改动,触发器还是建在源表上为好,另外建一个同源视图,赋予它相应的UPDATE权限,在?.........
应该是不行的.
触发器建在原表上, 触发器执行时, 原表及其视图是不可见的(MUTATING).
所以我给的解决方案中建议:
1. 改原表名; 2. 用原表名建视图; 3. 建触发器在视图上.
追风篮人 回复于:2004-08-12 13:01:40
是啊,试过了,仍然是同样的错误,的确是不行的;
在源表上建的触发器代码中无法修改源表,提示源表已被修改,无法对源表做更新操作。触发器代码中对视图操作也是实际上也是修改源表,所以也不行。
那么我再试试楼上的办法看看。。。
rollingpig 回复于:2004-08-12 13:18:39
From Metalink
Problem Description -------------------
Oracle does not allow you to read a mutating table in a row trigger because if you can read it, the information may be incorrect (not read consistent). If you attempt this, the following error is returned:
ORA-04091
Table %s.%s is mutating, trigger/function may not see it
However, you can perform this operation in a statement trigger.
One way to handle this situation is to use a package PL/SQL table to store ROWIDs of updated records in a row trigger, and reprocess the updated
records in a statement trigger.
Below is an example.
Important Note --------------
Note that there are concurrency issues with this if more than one session tries to perform operations simultaneously.
This is not intended as a total solution, but as the framework to help show one option.
Example Workaround ------------------
create or replace package emp_pkg as
type
emp_tab_type is table of rowid index by binary_integer;
emp_tab
emp_tab_type;
emp_index binary_integer;
end emp_pkg;
/
create or replace trigger emp_bef_stm_all
before insert or update or delete on emp
begin
/*
Remember to reset the pl/sql table before each statement
*/
emp_pkg.emp_index := 0;
end;
/
create or replace trigger emp_aft_row_all
after insert or update or delete on emp
for each row
begin
/*
Store the rowid of updated record into global pl/sql table
*/
emp_pkg.emp_index := emp_pkg.emp_index + 1;
emp_pkg.emp_tab(emp_pkg.emp_index) := :new.rowid;
end;
/
create or replace trigger emp_aft_stm_all
after
insert or update or delete on emp
begin
for i in 1 .. emp_pkg.emp_index loop
/*
Re-process the updated records.
There is no restriction here.
*/
dbms_output.put_line(emp_pkg.emp_tab(i));
end loop;
emp_pkg.emp_index := 0;
end;
/
huanggzcn 回复于:2004-10-09 13:10:54
试试我的办法,把for each row删除应该就可以了。
z-fh 回复于:2004-10-09 16:22:52
用trigger 来改同一表的记录没必要吧!我想trigger 的主要作用就是改别的表(特别是主从表记录)。同一表你在保存时写一下sql:
update A set parent_id = u_orig_value where A_id = :value ;
update 的条件是你的主键,别忘了记录不存在时 insert into A
|