今天遇到一个客户的问题,问题是浪潮ps软件(pb开发的c/s架构下的client端软件)有一个复选框是默认"打钩"的,而客户这边,根据业务的要求,这个复选框是不打钩的,于是跟软件开发工程师沟通了一下,开发工程师感觉这个不是通用需求,建议我用触发器解决这个问题.我想了一下,感觉也可以.于是就自己弄了一个触发器,如下:
CREATE OR REPLACE TRIGGER TRI_KCYXZ1_SFJCHZ
BEFORE update or insert on KCYXZ1
for each row
declare PJLX varchar2(1);
begin
PJLX:=:NEW.KCYXZ1_PJLX;
IF (PJLX='M') THEN
UPDATE KCYXZ1 SET
KCYXZ1.KCYXZ1_SFJCHZ='0'
WHERE KCYXZ1_LSBH=:NEW.KCYXZ1_LSBH;
END IF;
end;
这个触发器,在oracle中compile是没有问题的,但是前台软件使用此表(KCYXZ1)对应的功能的时候,报错(用sql monitor跟踪如下):
----------------------------------
Timestamp: 09:01:38.265
update KCYXZ1 SET KCYXZ1_LSBH =KCYXZ1_LSBH WHERE KCYXZ1_LSBH =:1
:1 = '1053'
Runtime error occurred: 4091 (ORA-04091: 表 LC0039999.KCYXZ1 发生了变化, 触发器/函数不能读它
ORA-06512: 在 "LC0039999.TRI_KCYXZ1_SFJCHZ", line 7
ORA-04088: 触发器 'LC0039999.TRI_KCYXZ1_SFJCHZ' 执行过程中出错)
----------------------------------
从google.com上看了一下这个问题,发现这个是属于变异表(mutating table)的触发器的问题,详细见如下帖子
http://blog.oracle.com.cn/html/58/t-120858.html
此贴子中有如下的描述,我感觉比较有意义,摘录下来:
触发器中的SQL语句不能:
读取或更新触发语句的任何变异表也包括触发表本身,读取或更新该触发表的约束表的主键列、唯一性键列或外键列但是如果需要也可以更新其他列。这些限制约束适用于所有行级触发器。但有个特例就是如果INSERT只影响一行记录那么定义在这行上的行级BEFORE和AFTER触发器就不会将这个触发表当作变异表。
有另外一个帖子说到:
触发器可以包括任何合法的PL/sQL语句,假有以下例外
1.触发器不可以执行COMMIT、ROLLBACK或SAVEPOINT语句,而且不可以调用执行这些语句之一的函数或过程。
2.触发器不可以声明long或LONG RAW变量。
3.触发器不可以在定义它的表上执行DML操作。
我自己写的这个触发器恰恰就违反了"3.触发器不可以在定义它的表上执行DML操作"这个条件.
于是咨询了一下开发工程师,并且在http://www.cnblogs.com/luyongqun/archive/2007/11/19/964470.html帖子的启发下,采用直接赋值的方式,避免了使用update 等dml语句,巧妙的达到了目的.
改后的触发器为(粗体蓝字的为修改了的语句):
CREATE OR REPLACE TRIGGER TRI_KCYXZ1_SFJCHZ
BEFORE update or insert on KCYXZ1
for each row
declare PJLX varchar2(1);
begin
PJLX:=:NEW.KCYXZ1_PJLX;
IF (PJLX='M') THEN
:NEW.KCYXZ1_SFJCHZ:='0';
END IF;
end;
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/161195/viewspace-612520/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/161195/viewspace-612520/