我有一个表触发器,当状态从2变为3时调用过程。过程检查整个数据组(group_id)是否处于状态3,然后执行某些操作。
但现在我遇到的问题是,当我同时在状态3中设置整组数据时,程序会被多次调用并多次执行此操作。我怎么能阻止他?例如,使用锁
这是我的程序查询:
SELECT COUNT(*)
INTO nResult
FROM ticket
WHERE group_id = nGroupId
AND statusid BETWEEN 0 AND 2;
/* If not all tickets of group in status 3, no action required */
IF nResult != 0 THEN
RETURN;
END IF;
这是我的触发器:
IF (:NEW.STATUSID = 3 AND :OLD.STATUSID = 2) THEN
myprocedure(:NEW.group_id);
END IF;
答案 0 :(得分:1)
您可能有一个行级触发器,每次更新行时都会触发;例如:
SQL> create table trigger_table(status number);
Table created.
SQL> insert into trigger_table values (1);
1 row created.
SQL> insert into trigger_table values (2);
1 row created.
SQL> insert into trigger_table values (3);
1 row created.
SQL> create trigger update_trigger
2 after update on trigger_table
3 for each row /* ROW LEVEL */
4 begin
5 dbms_output.put_line('change');
6 end;
7 /
Trigger created.
SQL> set serveroutput on
SQL> update trigger_table set status = 1;
change
change
change
3 rows updated.
您需要一个表级触发器,在每个更新语句后触发:
SQL> create or replace trigger update_trigger
2 after update on trigger_table
3 begin
4 dbms_output.put_line('change');
5 end;
6 /
Trigger created.
SQL> update trigger_table set status = 1;
change
3 rows updated.
Here你会发现更多内容。
正如Nicholas Krasnov正确观察到的那样,在这种触发器中,考虑一组行而不是一行,你没有:new
或:old
值。
获得您需求的方法可能如下,但这是一个棘手的解决方案,我会在生产环境中使用之前仔细检查。
你可以创建一个信号量表来知道你是否必须触发触发器,然后使用两个触发器,一个在行级别,一个在更新之前,一个在表级别,AFTER更新;行级别1检查值并更新信号量表,而更新后触发的表级别1读取信号量,调用您的过程(如有必要),然后重置信号量。 例如:
SQL> create table trigger_table(status number);
Table created.
SQL> insert into trigger_table values (1);
1 row created.
SQL> insert into trigger_table values (2);
1 row created.
SQL> insert into trigger_table values (3);
1 row created.
SQL> create table checkChange (fire varchar2(3));
Table created.
SQL> insert into checkChange values ('NO');
1 row created.
SQL> create or replace trigger before_update_trigger
2 before update on trigger_table
3 for each row /* ROW LEVEL */
4 begin
5 if :new.status = 3 and :old.status = 2 then
6 update checkChange set fire = 'YES';
7 end if;
8 end;
9 /
Trigger created.
SQL> create or replace trigger after_update_trigger
2 after update on trigger_table
3 declare
4 vFire varchar2(3);
5 begin
6 select fire
7 into vFire
8 from checkChange;
9 if vFire = 'YES' then
10 dbms_output.put_line('change');
11 update checkChange set fire = 'NO';
12 end if;
13 end;
14 /
Trigger created.
SQL> update trigger_table set status = 2;
3 rows updated.
SQL> update trigger_table set status = 3;
change
3 rows updated.
SQL>