首页  电脑故障排除  病毒安全 电脑基础知识  硬件知识  软件应用知识  操作系统知识  编程程序

美国编程网址 日本编程网址 法国编程网址 德国编程网址 韩国编程网址 香港编程网址 台湾编程网址

您的位置:首页>>编程程序>>Oracle

能否在表的触发器中当一记录变化修改另一记录

 
能否在表的触发器中当一记录变化修改另一记录
  
  :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如下:createorreplacetriggerU_EQUIPMENT_Essence_TRG
beforeupdateonU_EQUIPMENT_Essence
foreachrow
begin
updateu_equipment_essencesetequipment_original_value=equipment_original_value+:new.equipment_original_valuewhereu_equipment_essence_id=:new.u_main_equipment_essence_id
andu_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的阿,就是说我没办法找到当前修改的行,那么我只好写成如下:
CreateOrReplaceTriggerU_Equipment_Essence_After_Trg
afterupdate
onu_equipment_essence
declare
cursormain_equipmentis
selectu_equipment_essence_idfromu_equipment_essence
whereu_assembtype='M';
begin
forp1inmain_equipmentloop
updateu_equipment_essenceesset
es.equipment_original_value=(selectsum(equipment_original_value)fromu_equipment_essencewhereu_main_equipment_essence_id=es.u_equipment_essence_idandu_assembtype='P'),
es.month_depreciation_value=(selectsum(month_depreciation_value)fromu_equipment_essencewhereu_main_equipment_essence_id=es.u_equipment_essence_idandu_assembtype='P'),
es.year_depreciation_value=(selectsum(year_depreciation_value)fromu_equipment_essencewhereu_main_equipment_essence_id=es.u_equipment_essence_idandu_assembtype='P'),
es.u_ljzj=(selectsum(u_ljzj)fromu_equipment_essencewhereu_main_equipment_essence_id=es.u_equipment_essence_idandu_assembtype='P')
wherees.u_equipment_essence_id=p1.u_equipment_essence_id;
endloop;
endU_Equipment_Essence_After_Trg;
这样,运行时报错如下:ORA-00036:超过递归SQL(50)级的最大值
ORA-06512:在"CQSBGL.U_EQUIPMENT_ESSENCE_AFTER_TRG"
binary 回复于:2004-06-10 11:41:49
试试
.........
beforeupdateonU_EQUIPMENT_Essence
foreachrow
[color=red:945373285a]
DECLARE
PRAGMAAUTONOMOUS_TRANSACTION;
[/color:945373285a]
begin
updateu_equipment
..........
应该没有问题了
duwenhua 回复于:2004-06-10 11:42:39
如下的也报错:ORA-04091:表CQSBGL.U_EQUIPMENT_ESSENCE发生了变化,触发器/函数不能读
createorreplacetriggerU_EQUIPMENT_Essence_TRG
beforeupdate
ofequipment_original_value
onU_EQUIPMENT_Essence
foreachrow
when(new.u_assembtype='P')
begin
updateu_equipment_essenceset
equipment_original_value=equipment_original_value+:new.equipment_original_value
whereu_equipment_essence_id=:new.u_main_equipment_essence_id
andu_assembtype='M';
endU_EQUIPMENT_Essence_TRG;
duwenhua 回复于:2004-06-10 11:47:40
按光明使者老兄的改了,如下:
createorreplacetriggerU_EQUIPMENT_Essence_TRG1
beforeupdate
onU_EQUIPMENT_Essence
foreachrow
declare
PRAGMAAUTONOMOUS_TRANSACTION;
begin
updateu_equipment_essenceset
equipment_original_value=equipment_original_value+:new.equipment_original_value
whereu_equipment_essence_id=:new.u_main_equipment_essence_id
andu_assembtype='M';
endU_EQUIPMENT_Essence_TRG1;
但还不行:ORA-00060:等待资源时检测到死锁
ORA-06512:在"CQSBGL.U_EQUIPMENT_ESSENCE_TRG1",line4
duwenhua 回复于:2004-06-10 11:49:07
我变动了一下,如下:
createorreplacetriggerU_EQUIPMENT_Essence_TRG1
beforeupdate
ofequipment_original_value
onU_EQUIPMENT_Essence
foreachrow
when(new.u_assembtype='P')
declare
PRAGMAAUTONOMOUS_TRANSACTION;
begin
updateu_equipment_essenceset
equipment_original_value=equipment_original_value+:new.equipment_original_value
whereu_equipment_essence_id=:new.u_main_equipment_essence_id
andu_assembtype='M';
endU_EQUIPMENT_Essence_TRG1;
报错是:ORA-06519:检测到活动的自治事务处理,已经回退
ORA-06512:在"CQSBGL.U_EQUIPMENT_ESSENCE_TRG1",line10
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
Youcando:
1.Renameyourtablewithanothername;
2.Createaviewforselect*fromthetablewiththeoriginalnameofthetable;
3.Createainsteadoftriggerontheview,intheviewyoucanaccessandupdateyurbasetable.
Exampleofinsteadoftriggerforthiscase:
[CodeStart]
createtablet1(
idnumber(6)primarykey
,pidnumber(6)
,valuenumber(15,2)
,f1varchar2(10)
,f2varchar2(20)
);
createorreplaceviewt1_vasselect*fromt1;
createorreplacetriggerbug_t1_v
insteadofupdateont1_v
foreachrow
declare
procedureupdate_parents(i_idinnumber,i_valueinnumber);
procedureupdate_parents(i_idinnumber,i_valueinnumber)is
begin
declare
l_pidt1.pid%type;
begin
selectpidintol_pid
fromt1
whereid=i_id;
ifl_pid<>0then
updatet1setvalue=nvl(value,0)+nvl(i_value,0)
whereid=l_pid;
update_parents(l_pid,i_value);
endif;
exception
whenno_data_foundthen
null;
end;
endupdate_parents;
begin
--
--UpdateValueFieldforcurrentrecordandParentrecords
--
ifnvl(:new.value,0)-nvl(:old.value,0)<>0then
updatet1setvalue=value+nvl(:new.value,0)-nvl(:old.value,0)
whereid=:new.id;
update_parents(:new.id,nvl(:new.value,0)-nvl(:old.value,0));
endif;
--
--UpdateOthersFields
--
updatet1setf1=:new.f1
,f2=:new.f2
whereid=:new.id;
end;
--
--Testing
--
--Withthisview:t1_v
--
begin
foriin1..50loop
Insertintot1_vvalues(i,i-1,0,'','');
endloop;
end;
/
deletefromt1_v;
begin
foriin1..50loop
Insertintot1_vvalues(i,i-1,0,'','');
endloop;
end;
/
updatet1_vsetf1='TEST'whereid=49;
updatet1_vsetvalue=value+5,f1='AA',F2='BB'
whereid=50;
[CodeEnd]
追风篮人 回复于:2004-08-11 21:57:16
高手,GOODIDEA!
这个主意不错,可以借鉴一下,明天去单位试试。
利用这个思想,稍微做一下改动。
源表因为是业务表,不宜做改动,触发器还是建在源表上为好,另外建一个同源视图,赋予它相应的UPDATE权限,在该触发器中再对视图做UPDATE操作更新视图的相应其它字段。。。
还不知道这种方法是否可行,明天试了再回复。。。
byheart 回复于:2004-08-12 12:47:26
[quote:41e49e238f="追风篮人"]高手,GOODIDEA!
这个主意不错,可以借鉴一下,明天去单位试试。
利用这个思想,稍微做一下改动。
源表因为是业务表,不宜做改动,触发器还是建在源表上为好,另外建一个同源视图,赋予它相应的UPDATE权限,在?.........[/quote:41e49e238f]
应该是不行的.
触发器建在原表上,触发器执行时,原表及其视图是不可见的(MUTATING).
所以我给的解决方案中建议:
1.改原表名;2.用原表名建视图;3.建触发器在视图上.
追风篮人 回复于:2004-08-12 13:01:40
是啊,试过了,仍然是同样的错误,的确是不行的;
在源表上建的触发器代码中无法修改源表,提示源表已被修改,无法对源表做更新操作。触发器代码中对视图操作也是实际上也是修改源表,所以也不行。
那么我再试试楼上的办法看看。。。
rollingpig 回复于:2004-08-12 13:18:39
FromMetalink
ProblemDescription-------------------
Oracledoesnotallowyoutoreadamutatingtableinarowtriggerbecauseifyoucanreadit,theinformationmaybeincorrect(notreadconsistent).Ifyouattemptthis,thefollowingerrorisreturned:
ORA-04091
  Table%s.%sismutating,trigger/functionmaynotseeit
  However,youcanperformthisoperationinastatementtrigger.
  OnewaytohandlethissituationistouseapackagePL/SQLtabletostoreROWIDsofupdatedrecordsinarowtrigger,andreprocesstheupdated
  recordsinastatementtrigger.
Belowisanexample.
ImportantNote--------------
  Notethatthereareconcurrencyissueswiththisifmorethanonesessiontriestoperformoperationssimultaneously.
  Thisisnotintendedasatotalsolution,butastheframeworktohelpshowoneoption.
ExampleWorkaround------------------
[code:1:50147eb56b]
createorreplacepackageemp_pkgas
type
emp_tab_typeistableofrowidindexbybinary_integer;
emp_tab
emp_tab_type;
emp_indexbinary_integer;
endemp_pkg;
/
createorreplacetriggeremp_bef_stm_all
beforeinsertorupdateordeleteonemp
begin
/*
Remembertoresetthepl/sqltablebeforeeachstatement
*/
emp_pkg.emp_index:=0;
end;
/
createorreplacetriggeremp_aft_row_all
afterinsertorupdateordeleteonemp
foreachrow
begin
/*
Storetherowidofupdatedrecordintoglobalpl/sqltable
*/
emp_pkg.emp_index:=emp_pkg.emp_index+1;
emp_pkg.emp_tab(emp_pkg.emp_index):=:new.rowid;
end;
/
createorreplacetriggeremp_aft_stm_all
after
insertorupdateordeleteonemp
begin
foriin1..emp_pkg.emp_indexloop
/*
Re-processtheupdatedrecords.
Thereisnorestrictionhere.
*/
dbms_output.put_line(emp_pkg.emp_tab(i));
endloop;
emp_pkg.emp_index:=0;
end;
/
[/code:1:50147eb56b]
huanggzcn 回复于:2004-10-09 13:10:54
试试我的办法,把foreachrow删除应该就可以了。
z-fh 回复于:2004-10-09 16:22:52
用trigger来改同一表的记录没必要吧!我想trigger的主要作用就是改别的表(特别是主从表记录)。同一表你在保存时写一下sql:
updateAsetparent_id=u_orig_valuewhereA_id=:value;
update的条件是你的主键,别忘了记录不存在时insertintoA
  

查看上一页  返回分类首页 返回96PC首页  查看下一页

  版权所有:电脑知识大全 网站备案:粤ICP备07031496号  联系我们

友情链接:母婴知识  外贸商务网  娱乐频道  汽车维修知识  股票入门知识  游戏攻略秘籍  本站空间由安信网络提供