下面是一个oracle的trigger,创建的时候没有问题,但是update操作的时候,
出现ORA-04091错误,也就是对行触发器来讲,对当前正在改变的表不允许做select操作,但是如果不用行触发器的话,无法知道当前改变的列的值,哪位高人能指点一二,万分感谢。
CREATE OR REPLACE TRIGGER TRIGGER_PING_MONITOR
AFTER DELETE OR INSERT OR UPDATE OF RecordStatus ON PINGMONITOR_ADMIN
FOR EACH ROW
DECLARE
v_num NUMBER;
BEGIN
SELECT COUNT(*) INTO v_num FROM PINGMONITOR_ADMIN WHERE PINGMONITOR_ADMIN.PingMonitorID=:NEW.PingMonitorID AND PINGMONITOR_ADMIN.RecordStatus=0;
IF v_num>;0 THEN
UPDATE NODE_ADMIN SET PingMonitor = 1
WHERE NODE_ADMIN.NodeID=:NEW.PingMonitorID;
ELSE
UPDATE NODE_ADMIN SET PingMonitor = 0
WHERE NODE_ADMIN.NodeID=:NEW.PingMonitorID;
END IF;
END TRIGGER_PING_MONITOR;
/
SQL>; desc PINGMONITOR_ADMIN ;
名前 NULL? 型
----------------------------------------- -------- -------------
PINGMONITORID NOT NULL VARCHAR2(15)
PINGMONITORCNT NOT NULL NUMBER(2)
RECORDSTATUS NUMBER(1)
RECORDUPDATETIME DATE
RECORDCREATETIME DATE
SQL>; desc NODE_ADMIN
名前 NULL? 型
----------------------------------------- -------- ------------------
NODEID NOT NULL VARCHAR2(15)
IP VARCHAR2(40)
GLOBALIP VARCHAR2(40)
HOSTNAME VARCHAR2(64)
PINGMONITOR NUMBER(1)
SERVICEPORTMONITOR NUMBER(1)
PROCESSMONITOR NUMBER(1)
RESOURCEMONITOR NUMBER(1)
LOGMONITOR NUMBER(1)
SNMP_TRAPMONITOR NUMBER(1)
RECORDSTATUS NUMBER(1)
RECORDUPDATETIME DATE
RECORDCREATETIME DATE
|
trigger问题求助
你的PINGMONITOR_ADMIN.PingMonitorID是primary key吗?如是 把IF v_num>;0 THEN 改为 if :NEW.PINGMONITOR_ADMIN.RecordStatus=0 then 如不是primary key 那是哪一个 能否把你的意图写一下,表中是否有重复行 一般来说insert or update tigger写在一起的话,可用 if inserting then --如果是插入 --这时候可以引用:NEW.PINGMONITOR_ADMIN.RecordStatus,但:OLD.PINGMONITOR_ADMIN.RecordStatus是空的 else --如果是update --这时:OLD,:NEW都可以引用 end if 我昨天也遇上这个问题,确实不能触发器上对触发表做SELECT |
|
trigger问题求助
谢谢你的回答.
PINGMONITOR_ADMIN.PingMonitorID和PINGMONITOR_ADMIN.PINGMONITORCNT是primary key 可能是我没说清楚.
是UPDATE或者DELETE的时候,我需要知道PINGMONITOR_ADMIN里符合条件的 记录有没有再去更新NODE_ADMIN.
你的解决方法只能对应UPDATE一条记录的情况.这时候我并不能知道PINGMONITOR_ADMIN里符合条件的记录有没有. |
|
trigger问题求助
你根本不用去判断 假设你的update或delete是由 update(or delete) PINGMONITOR_ADMIN set PINGMONITOR_ADMIN.RecordStatus=0 where PINGMONITOR_ADMIN.PingMonitorID=条件 and PINGMONITOR_ADMIN.RecordStatus=0;来触发的 那么你直接引用:NEW和:OLD就行了 注意:delete 是没有 :NEW的 如不是上面的假设触发条件,那你把可能的引起触发的语句都写一下行吗? 包括insert,update,delete |
|
trigger问题求助
问题是我不知道update,delete是的where条件.
就个例子: PINGMONITOR_ADMIN 中有以下几条记录: PINGMONITORID ,PINGMONITORCNT,RECORDSTATUS,RECORDUPDATETIME,RECORDCREATETIME A1,1,0, , A1,2,0, , A1,3,0, , A1,4,9, , 这时候NODE_ADMIN.PingMonitor =1,如果我删除 A1,1,0, , 那么NODE_ADMIN.PingMonitor还是1 如果我删除 A1,1,0, , A1,2,0, , A1,3,0, , 那么NODE_ADMIN.PingMonitor=0 |
|
trigger问题求助
根据你的trigger 我以为使用表级触发器就可以,使用表级触发不能满足你的要求吗?非得要使用行级触发吗? |
|
trigger问题求助
可以使用表级触发器的,但是我不熟. 愿闻其详. 谢了先. |
|
trigger问题求助
把for each row去掉就可以了。 |
|
trigger问题求助
把fro each row去掉也不一定行,因为它要对本表进行查询,可以编译通过,但在运行时却提示本表已被改变。 对于本贴可采用以下办法。 建立一个对表PINGMONITOR_ADMIN中PingMonitorID的数量的监控表 create table pingmon as select PingMonitorID,count(*) coun from PINGMONITOR_ADMIN where RecordStatus=0 group by PingMonitorID; 在表PINGMONITOR_ADMIN上建立两个触发器,一个before 一个after create or replace trigger PINGMONITOR_ADMIN_BE before delete on PINGMONITOR_ADMIN for each row begin update pingmon set coun=coun-1 where PINGMONITORid=:OLD.PINGMONITORid; --因为这是个行级触发器,所以每删除一行就会在监控表pingmon上相应coun上减1 if sql%rowcount=0 then insert into pingmon values (:OLD.PINGMONITORid,1); --如果在监控表上无相应的行,就插入一行 end if; end;
create or replace trigger PINGMONITOR_ADMIN_AF after delete on PINGMONITOR_ADMIN for each row begin UPDATE NODE_ADMIN a SET PingMonitor = (select decode(nvl(coun,0),0,0,1) from pingmon b where a.PINGMONITORid=b.PINGMONITORid(+)) --如果监控表上相应行coun为零,NODE_ADMIN就置0,否则置1 end; 你还要做insert和update的触发器来维护pingmon、NODE_ADMIN和PINGMONITOR_ADMIN的一致性问题,这是关键问题 |
|
trigger问题求助
[quote][i]原帖由 "OL.O" 发表:[/i] 把fro each row去掉也不一定行,因为它要对本表进行查询,可以编译通过,但在运行时却提示本表已被改变。 [/quote]
really ?
NO!! |
|
trigger问题求助
[quote][i]原帖由 "nyfor" 发表:[/i]
really ?
NO!![/quote] 您能用您的方法解决一下最上面的问题吗?请教!! |
|
trigger问题求助
还是nyfor说得对,我的方法太复杂了 谢谢nyfor |
老鼠(Unix is my |
2003-4-4 04:28 | |
trigger问题求助
[quote][i]原帖由 "kasyunn" 发表:[/i] 下面是一个oracle的trigger,创建的时候没有问题,但是update操作的时候, 出现ORA-04091错误,也就是对行触发器来讲,对当前正在改变的表不允许做select操作,但是如果不用行触发器的话,无法知道当前改变的列的值?.........[/quote]
原始要求是什么? |
|
trigger问题求助
[quote][i]原帖由 "kasyunn" 发表:[/i] 下面是一个oracle的trigger,创建的时候没有问题,但是update操作的时候, 出现ORA-04091错误,也就是对行触发器来讲,对当前正在改变的表不允许做select操作,但是如果不用行触发器的话,无法知道当前改变的列的值?.........[/quote] 上面问题中要把 FOR EACH ROW去掉后 就不能引用:OLD和:NEW了 |
|
trigger问题求助
[quote][i]原帖由 "OL.O" 发表:[/i] 还是nyfor说得对,我的方法太复杂了 谢谢nyfor[/quote] 我刚才做了一下测试,也不一定对,去掉FOR EACH ROW后 不能引用:OLD和:NEW,那最上面的那个触发器就不能编译成功。
还是要谢谢nyfor |
|
trigger问题求助
谢谢. 看来还是得增加一个临时表.
这样应该可以解决了. |
|
trigger问题求助
那还不如建立一个view使用instead of 触发器。 |
|
trigger问题求助
经过一番折腾后我想了一个简单而又有效的办法,只用一个语句级触发器就可搞定 CREATE OR REPLACE TRIGGER TRIGGER_PING_MONITOR AFTER DELETE OR INSERT OR UPDATE OF RecordStatus ON PINGMONITOR_ADMIN BEGIN INSERT INTO NODE_ADMIN SELECT B.PingMonitorID,1 FROM NODE_ADMIN A,PINGMONITOR_ADMIN B WHERE A.NODEID(+)=B.PingMonitorID AND B.RecordStatus=0 AND A.NODEID IS NULL; --当插入一个在NODE_ADMIN里没有的行时的处理,如果有相应的行在NODE_ADMIN就无行被插入 UPDATE NODE_ADMIN A SET PINGMONITOR=(SELECT DECODE(COUNT(*),0,0,1) FROM PINGMONITOR_ADMIN B WHERE A.NODEID=B.PingMonitorID AND B.RecordStatus=0); END TRIGGER_PING_MONITOR; --每次事务都对NODE_ADMIN进行一次刷新,这样就不存在一致性问题了,前面我的答复虽然也可完成相应的功能,但还要有很多加工,这个就不必改太多了
|