badfsaadkl
Goto Top

Oracle Procedure Aufruf im Trigger

Moin zusammen,

ich habe ein kleines Problem, einen Datenbank Trigger zum laufen zu bekommen, und hoffe Ihr könnt mir hier helfen.
Ich habe eine Procedure geschrieben, welche ein Update auf eine Tabelle macht, und 2 Parameter benötigt.
Anbei mal die Procedure
create or replace 
procedure add_flugstunden
  (
  p_per_nr in osq01_pilot.per_nr%TYPE,
  p_bez in osq01_flug.f_bez%TYPE
  )
  is
  BEGIN
   	declare
    	cursor cur_get_data
    	is
    		select
      			pil.p_std,
      			flg.zeit
    		from
      		osq01_pilot pil,
      		osq01_flug flg,
      		osq01_abflug aflg
    		where
      			aflg.f_bez = flg.f_bez and
      			aflg.per_nr = pil.per_nr and
      			aflg.f_bez = p_bez
    	;
    	
    	v_p_std   osq01_pilot.p_std%TYPE;
    	v_zeit    osq01_flug.zeit%TYPE;
    	
  		begin
    		open cur_get_data;
          fetch cur_get_data into v_p_std, v_zeit;
    			update osq01_pilot
    			set p_std = v_p_std + v_zeit
    			where
      			per_nr = p_per_nr;
    		close cur_get_data;
    	end;
  END add_flugstunden;

Nun brauche ich einen Trigger, der jedesmal wenn auf eine bestimmte Tabelle ein Update oder Insert gemacht wird, der Trigger ausgelöst wird.
Aktuell sieht mein Trigger wie folgt aus:
create or replace trigger tr_add_flugstunden
after insert or update on osq01_abflug
for each row
begin
  add_flugstunden(:new.per_nr, :new.f_bez);
end tr_add_flugstunden;
/

Der Trigger wurde soweit auch erstellt.
Jedoch wenn ich einen Insert auf die Tabelle osq01_abflug mache, erhalte ich folgende Fehlermeldung:
Fehlerbericht:
SQL-Fehler: ORA-04091: table SGD.OSQ01_ABFLUG is mutating, trigger/function may not see it
ORA-06512: at "SGD.ADD_FLUGSTUNDEN", line 11  
ORA-06512: at "SGD.ADD_FLUGSTUNDEN", line 28  
ORA-06512: at "SGD.TR_ADD_FLUGSTUNDEN", line 2  
ORA-04088: error during execution of trigger 'SGD.TR_ADD_FLUGSTUNDEN'  
04091. 00000 -  "table %s.%s is mutating, trigger/function may not see it"  
*Cause:    A trigger (or a user defined plsql function that is referenced in
           this statement) attempted to look at (or modify) a table that was
           in the middle of being modified by the statement which fired it.
*Action:   Rewrite the trigger (or function) so it does not read that table.

Anbei auch mein Insert Befehl:
INSERT INTO OSQ01_ABFLUG( F_BEZ, AB_DATUM, PER_NR, HERST, TYP, SER_NR, AB_ZEIT)
VALUES ('LH-341','14.11.06','10010001','Boeing','B737','ba23-0012','10,23')  

Hat jemand eine Idee wo hier mein Fehler liegt und kann mir helfen ?

Danke

Gruß
BadFsaadKl

Content-Key: 241844

Url: https://administrator.de/contentid/241844

Printed on: April 25, 2024 at 01:04 o'clock

Member: Biber
Solution Biber Jun 25, 2014, updated at Jun 26, 2014 at 18:25:14 (UTC)
Goto Top
Moin BadFsaaKl,

soweit ich deine Tabellenstruktur verstehe, kannst du doch wirklich auf ein Lesen der "Abflug"-Tabelle verzichten, wie in der Fehlermeldung nahegelegt.

Deine procedure sollte auch so funktionieren:
create or replace 
procedure add_flugstunden
  (
  p_per_nr in osq01_pilot.per_nr%TYPE,
  p_bez in osq01_flug.f_bez%TYPE
  )
  is
  BEGIN
   	declare
    	cursor cur_get_data
    	is
    		select
      			pil.p_std,
      			flg.zeit
    		from
      		osq01_pilot pil,
      		osq01_flug flg
    		where
      	                pil.per_nr = p_per_nr
      			flg.f_bez = p_bez
    	;
    	
    	v_p_std   osq01_pilot.p_std%TYPE;
    	v_zeit    osq01_flug.zeit%TYPE;
    	
  		begin
    		open cur_get_data;
          fetch cur_get_data into v_p_std, v_zeit;
    			update osq01_pilot
    			set p_std = v_p_std + v_zeit
    			where
      			per_nr = p_per_nr;
    		close cur_get_data;
    	end;
  END add_flugstunden;
...denn das bisher "joinende" Kriterium "aflg.f_bez = flg.f_bez and aflg.per_nr = pil.per_nr and aflg.f_bez = p_bez" läuft doch -ins Deutsche übersetzt- darauf hinaus, dass du jeweils genau einen Satz aus drei Tabellen liest und als Kreuzprodukt (1row*1*row*1row) dann eben auch genau einen Satz im Resultset erhältst.
Das geht auch als Kreuzprodukt aus zwei Tabellen. face-wink

Ich verstehe nicht, warum du einen Cursor verwendest... Trigger beziehen sich doch üblicherweise auf EINEN Datensatz, der INSERTed/UPDATEd oder DELETEd wird - so wie bei dir.
Trigger mit dem Scope "TABLE" gibt es auch - aber den brauchst du doch nicht in deinem Fall.

Ein Update oder Insert in der Abflug-Tabelle führt doch immer nur zu genau einem Folge-Update-Datensatz in der "Pilotstunden"-Tabelle - oder lese ich das falsch?

Grüße
Biber
Member: BadFsaadKl
BadFsaadKl Jun 26, 2014 at 18:25:08 (UTC)
Goto Top
Biber,

du bist mein Held... :D
Ich hab mal wieder nur zu kompliziert gedacht.

Trigger funktioniert nun einwandfrei...

Danke dir.
Member: Biber
Biber Jun 26, 2014 updated at 19:26:49 (UTC)
Goto Top
Moin BadFsaadKl,


na ja, sagen wir so - der Trigger bringt wohl keine Fehlermeldung mehr.

Allerdings würde ich noch mal in Ruhe darüber meditieren
a) ob du überhaupt einen Cursor brauchst, den du dann vollständig vom ersten bis zum ...ähmmm... ersten Satz durchfetchst - dafür würde auch ein einfaches direktes "UPDATE pilotentabelle" reichen IMHO.
b) und vor allem, ob denn wirklich bei jedem UPDATE in der abflug-Tabelle nochmal die Stunden in der Piloten-Tabellen addiert werden sollen.

Bei einem INSERT ja, durchaus.
Bei einem noch zu ergänzenden DELETE-Trigger auf der Abflug-Tabellen könnten ebenso blind wieder Stunden in der Pilotentabelle rausgerechnet werden.

Bei einem Update der Abflug-Tabelle, z.B weil jemand einen Tippfehler im Feld "Typ" von "Boeing 773" zu "Boeing 737" korrigiert - da kann es doch noch nicht sein, dass deswegen nochmals die Flugzeitstunden einem Piloten gutgeschieben werden.

Weil - die verdienen ohnehin schon genug.

Ich würde - schon zu Übungszwecken - nochmal
  • einen UPDATE-Trigger schreiben (der nur bei einer Änderung der Felder "per_nr" und/oder "f_bez" feuert - denn in diesen Fällen müssen die bereits gebuchten Pilotenstunden reduziert werden und einem anderen Piloten gutgeschrieben werden)
  • und den fehlenden DELETE-Trigger musst du ohnehin schreiben, es sei denn, ein Löschen eines Datensatzes der Abflug-Tabelle ist absolut ausgeschlossen.

Grüße
Biber