trigger问题收藏

下面是一个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
OL.O 2003-4-3 03:56
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

kasyunn 2003-4-3 05:05
trigger问题求助 

谢谢你的回答.

PINGMONITOR_ADMIN.PingMonitorID和PINGMONITOR_ADMIN.PINGMONITORCNT是primary key
可能是我没说清楚.

是UPDATE或者DELETE的时候,我需要知道PINGMONITOR_ADMIN里符合条件的
记录有没有再去更新NODE_ADMIN.

你的解决方法只能对应UPDATE一条记录的情况.这时候我并不能知道PINGMONITOR_ADMIN里符合条件的记录有没有.

OL.O 2003-4-3 05:44
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

kasyunn 2003-4-3 06:03
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

nyfor 2003-4-3 07:47
trigger问题求助 

根据你的trigger 我以为使用表级触发器就可以,使用表级触发不能满足你的要求吗?非得要使用行级触发吗?

kasyunn 2003-4-3 08:34
trigger问题求助 

可以使用表级触发器的,但是我不熟.
愿闻其详.
谢了先.

nyfor 2003-4-3 12:37
trigger问题求助 

把for each row去掉就可以了。

OL.O 2003-4-4 03:19
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的一致性问题,这是关键问题

nyfor 2003-4-4 04:02
trigger问题求助 

[quote][i]原帖由 "OL.O" 发表:[/i]
把fro each row去掉也不一定行,因为它要对本表进行查询,可以编译通过,但在运行时却提示本表已被改变。
[/quote]

really ?

NO!!

OL.O 2003-4-4 04:20
trigger问题求助 

[quote][i]原帖由 "nyfor" 发表:[/i]


really ?

NO!![/quote]
您能用您的方法解决一下最上面的问题吗?请教!!

OL.O 2003-4-4 04:26
trigger问题求助 

还是nyfor说得对,我的方法太复杂了
谢谢nyfor

老鼠(Unix is my 2003-4-4 04:28
trigger问题求助 

[quote][i]原帖由 "kasyunn" 发表:[/i]
下面是一个oracle的trigger,创建的时候没有问题,但是update操作的时候,
出现ORA-04091错误,也就是对行触发器来讲,对当前正在改变的表不允许做select操作,但是如果不用行触发器的话,无法知道当前改变的列的值?.........[/quote]

原始要求是什么?

OL.O 2003-4-4 04:40
trigger问题求助 

[quote][i]原帖由 "kasyunn" 发表:[/i]
下面是一个oracle的trigger,创建的时候没有问题,但是update操作的时候,
出现ORA-04091错误,也就是对行触发器来讲,对当前正在改变的表不允许做select操作,但是如果不用行触发器的话,无法知道当前改变的列的值?.........[/quote]
上面问题中要把 FOR EACH ROW去掉后
就不能引用:OLD和:NEW了

OL.O 2003-4-4 04:53
trigger问题求助 

[quote][i]原帖由 "OL.O" 发表:[/i]
还是nyfor说得对,我的方法太复杂了
谢谢nyfor[/quote]
我刚才做了一下测试,也不一定对,去掉FOR EACH ROW后
不能引用:OLD和:NEW,那最上面的那个触发器就不能编译成功。


还是要谢谢nyfor

kasyunn 2003-4-4 05:35
trigger问题求助 

谢谢.
看来还是得增加一个临时表.

这样应该可以解决了.

nyfor 2003-4-4 07:35
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进行一次刷新,这样就不存在一致性问题了,前面我的答复虽然也可完成相应的功能,但还要有很多加工,这个就不必改太多了


posted on 2006-02-08 19:01 青蛙學堂 阅读(359) 评论(1)  编辑 收藏 引用 所属分类: 數據庫

评论

# re: trigger问题收藏 2006-02-08 19:05 -

表a id int
表b mc varchar(20) id int
对表a的id更新时触发,同步更新B表相应的id.
没写过trigger 能否给出例子?



回复人: liuyun2003(流云(快乐的生活在南宁中……)) ( ) 信誉:100 2003-06-18 10:27:52Z 得分:0


?
create trigger tri_update on a for update
as
update b set id=inserted.id where b.id=deleted.id
go


Top

回复人: xushu163(老二) ( ) 信誉:100 2003-06-18 10:28:48Z 得分:0


?
联级更新,代码如下:
if exists(select name from sysobjects where name='update_b' and type='tr')
drop trigger update_b
go
create trigger update_b
on a
with encryption
for update
as
update(id)
begin
DECLARE @id as char(4)
SELECT @id=id FROM inserted
UPDATE b
SET id=@id
from deleted
WHERE id=deleted.id
end





Top

回复人: xushu163(老二) ( ) 信誉:100 2003-06-18 10:32:14Z 得分:0


?
不好意思,上面有个地方写漏了,
update(id),应是:
if update(id)



Top

回复人: xushu163(老二) ( ) 信誉:100 2003-06-18 10:35:07Z 得分:0


?
其实如你只想完成上面的联级更新的话,用外键更好,效率高些!



  回复  更多评论   

只有注册用户登录后才能发表评论。
<2006年2月>
2930311234
567891011
12131415161718
19202122232425
2627281234
567891011

导航

统计

常用链接

留言簿(7)

随笔分类

随笔档案

收藏夹

青蛙学堂

最新评论

阅读排行榜

评论排行榜