2016-07-14 7 views
0

ステータスが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

は何回も呼び出されます - それは予想される動作です。 –

+0

はい、それは期待された動作ですが、今は同じグループに対してこのアクションを複数回並行して実行しないように防止する必要があります – ZerOne

答えて

1

おそらく行があるたびに発射された行レベルのトリガーを、持っています更新しました;例えば:あなたはより多くの何かを見つける

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

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. 

あなたはすべての更新ステートメントの後に解雇テーブル・レベルのトリガを、必要とします。

Nicholas Krasnovが正しく観察したように、この種類のトリガーでは、1つの行ではなく1つの行を考慮すると、:newまたは:oldという値はありません。 あなたのニーズを満たす方法は次のとおりですが、それは難解な解決策であり、運用環境で使用する前に注意深くチェックします。

トリガーを起動する必要があるかどうかを確認するためにセマフォー・テーブルを作成し、行レベルで1つ、行レベルで1つ、更新前に2つ、および表レベルで1つずつ、AFTER更新を使用できます。行レベル1は値をチェックしてセマフォ・テーブルを更新し、更新後に起動されたテーブル・レベル1はセマフォを読み込み、必要に応じてプロシージャを呼び出し、セマフォをリセットします。 は、たとえば:あなたは行レベルのトリガを作成しているので、2から3に多くの変更が発生したとして、あなたの説明の手順に基づいて

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> 
+0

@NicholasKrasnov:良い点は、OPを考慮した答えを編集したものです。ありがとう – Aleksej

+0

私は:新しいと古いプロパティが必要なので、これは私のニーズにとっては良い解決策ではありません。このニーズに対するoracle実装のロックはありませんか? – ZerOne

+0

@ ZerOne:あなたの質問に可能な解決策を示すために編集しました。 – Aleksej

関連する問題