今天在项目中遇到一个比较棘手的问题,需要用到触发器。在编写触发器和调试过程中遇到下列问题,在此记录一下:
创新互联公司10多年企业网站制作服务;为您提供网站建设,网站制作,网页设计及高端网站定制服务,企业网站制作及推广,对发电机维修等多个方面拥有多年的营销推广经验的网站建设公司。
由于之前写的触发器都能正常运行,就没有涉及到触发器的调试,今天发现触发器没起作用,需要调试,竟不知道在哪儿调试。在网上借鉴一些别人的经验(),记录一下。在PL/SQL中,触发器的调试方法如下:
1,选中要调试的触发器,右击,然后勾选 Add debug information,只有勾选这个按钮后,调试才能进入到断点。
2,选中触发器,点击 Edit,到Edit 界面,在要调试的行号前面单击,或者右键,添加断点。
3,在菜单的新建中选择“测试窗口”,打开一个如下块,在begin和end中间添加能触发触发器的语句
4,按F9或者点击调试菜单中的开始菜单,进入运行调试状态(后面的红框是单步进入)
5,点击运行图标跳到触发器中断点位置
6,鼠标放到变量上可以显示变量值。
7,如果有异常,就弹出相关异常信息。
调试的时候发现new对象的日期格式为中文,而后面又需要yyyy-mm-dd 的格式来作为查询条件。所以就在赋值的时候转换一下。
在select into 给变量赋值的时候,select 查询出来的集合为空,导致报错ORA-01403,解决方案就是将这一段用begin end 包裹起来,抛出改异常的时候给变量一个默认值。如下图:
1.引言 本人在做一个大型的MIS系统(前台用powerbuild工具 后台用oracle数据库)时 常碰到一些有关数据冗长性 批量删除和动态信息方面的问题 由此发现数据库触发器简单易用 现将有关开发和应用中的一些体会总结成文 供同行参考 2.触发器的概念和类型 数据库触发器(database triggers)是响应插入 更新或删除等数据库事件而执行的过程 它定义了当一些数据库相关事件发生时应采取的动作 可用于管理复杂的完整性约束 或监控对表的修改 或通知其它程序 表已发生修改 它的类型有 语句级触发器 以及行级触发器 前者可以在语句执行前或执行后被触发 后者在每个触发语句影响的行触发一次 还有before和after触发的命令 在insert update 和delete之前或之后执行 引用新旧值进行处理 如果需通过触发器设定插入行中的某列值 则为了访问 新(new) 值 需使用一个触发器before insert 使用after insert则不行 Instead of 触发器命令 使用它告诉oracle应执行什么操作 以上四种大类合成 种小类(略) 各种触发器的执行顺序如下 ⑴ 如果有 最先执行语句级before触发器 ⑵ 每个insert delete update影响的行 ①如果有 最先执行行级before ②执行行的delete或update ③如果有 执行行级after触发器 ⑶ 如果有 执行语句级after触发器 3.使用数据库触发器管理数据冗余性 为了数据分析和制作报表的需要 用户在数据模型中加入了冗余数据 应使用触发器 以保证数据的完整性 冗余数据可以用规定的 for each row选项的before update触发器进行管理 update 命令可放在触发器中对所有需要更新的冗余数据进行更新 如客户表和订单表 订单表包括客户的订单和客户表的冗余信息 客户表(customer)的表结构:客户号(cu_no) 客户名(cu_name) 客户地址(cu_address) 订单表(order)的表结构:订单号(or_no) 客户号(or_no) 客户名(cu_name) 客户地址(cu_address) 当客户基表中的数据被更新时更新订单中的冗余列 语法如下 create or replace trigger bj_customer before update on customer for each row begin update order set cu_no=:new cu_no cu_name=:new cu_name cu_address=:new cu_addess where cu_no=:old cu_no end; 4.用触发器完成数据复制 如果需求非常有限 可以用数据触发器从一个数据库中向另一个数据库复制数据 如果数据复制需求仅与数据的插入有关 当一条记录插入到一个数据库中的某个基表中时 用户还希望把这条记录插入到一个远程数据库中 需用create database link语句创建一条到远程数据库的连接 一旦创建了一条数据库连接后 就可以在基表上创建一个after insert触发器 以把每一条记录插入到远程数据库中 ( )在脚本中创建数据库连接(database link)bj_ysd_remote基表作为数据库基表 Bj_ysd_local代表本地数据库上的源基表 Creat database link remote(连接名) Connect to bj(帐户) indentified by bj(密码) Using : ; ( )复制记录 create or replace trigger trig_ysd(触发器名) after insert on bj_ysd_local for each row begin insert into bj_ysd_remote@dblink remote value(:new x :new x ……)/*x x 代表字段名*/ end; ( )删除记录 create or replace trigger trig_ysd_del after delete on bj_ysd_local for each row begin delete from bj_ysd_remote@dblink remote where x =:old x end; 5.用数据库触发器完成瀑布式删除操作 在某些情况下 当要删除一条记录时 该记录是与外键有关的另外一张基表上的记录时 这个删除操作必须在模型中进行传递 否则会出现大量的冗长数据 仍以cumstomer 和order基表为例 当从customer中删除一个客户时 order基表中所有相关记录也应当删除 Create or replace trigger trig_cust Before delete on customer For each row Begin Delete from order Where cu_no=old cu_no End; 6.用触发器完成动态数据的操作 在涉及如何实现动态库存的问题时 可用触发器解决 仓库有验收 出库 调拨 报废 退料 让售等这些数据必须与以前的库存相加减 才能完成动态库存操作 本文仅以验收单触发器为例 其它的结构雷同 它们涉及到两个基表 bi_ysd(验收单) Bj_kcb(当前库存表) 前者的表结构(rq(日期) ysdh(验收单号) bjbm(备件编码) yssl(验收数量) ysdj(验收单价)) 后者的表结构为(bjbm(备件编码) dqkcl(当前库存量) dqkcje(当前库存金额))触发器如下 create or replace trigger trig_ysd after insert or update or delete on bj_ysd for each row declare rq varchar ( );rq varchar ( ); /*限于篇幅 yssl yssl ysdj ysdj bjbm bjbm ii声明略*/ if inserting or updating then rq :=:new rq;bjbm :=:new bjbm;yssl :=:new yssl; ysdj :=:new ysdj; select count(*) into ii from bj_dqkcb where bjbm=bjbm ; if ii= then insert into bj_dqkcb(bjbm dqkcl dqkcje) value(bjbm yssl ysdj ); else update bj_dqkcb set dqkcl=dqkcl+yssl ; dqkcje=dqkcje+yssl *ysdj ; end if end if if deleting or updating then rq :=:old rq;bjbm :=:old bjbm;yssl :=:old yssl; ysdj :=:old ysdj; update bj_dqkcb set dqkcb=dqkcl yssl ; dqkcje=dqkcje yssl *ysdj end if; end ; 7.结束语 数据库触发器在数据库开发 MIS开发上有很广泛的应用 但经验表明 使用过多的触发器将降低整个数据库的性能 如果数据库触发器写得不好 它会很快破坏数据库的性能 因此 在适当的时候使用恰当的触发器显得非常重要 lishixinzhi/Article/program/Oracle/201311/18819
你可以建一个异常,在出现某种情况的时候,进入异常,就会退出触发器了。
trigger的触发条件是insert or update,他跟字段名无关,所以当你2个一起执行的时候,就会出现这样的情况:update 表534的时候,触发trigger:hjx_formtable534_inser
533也跟着update;接着触发hjx_formtable533_update,这时又把534也update了。从此走上死循环的不归路。。。。。。
其实可以这样(我不知道你哪个table1,哪个table2)。table1的trigger设置为affer,那么另外一个trigger设置为before,这样理论上应该可以同时触发2个 trigger而不会存在循环问题,我才下班,还没来得及试验,不好意思
表都已经删除了 触发器肯定是失效了,办法就是把创建触发器的脚本保留下来,创建表的时候重建触发器即可
--禁用
alter table [tablename]
disable all trigger
--恢复
alter table [tablename]
enable all trigger
如果你想禁用数据库中所有的触发器,那你只能写存储过程实现,找出所有的表,然后逐一禁用