SQL-Trigger (Ora) Bedingte Aktion?

Hallo,

ich möchte einen Trigger in der Art einer Indexierung aufbauen:
Beispiel:
In „TABELLE“ stehen Name und Telefonnummer.
In „TABCHANGE“ stehen Name und Datum der letzten Rufnummeränderung.
Die Namen sind in „TABELLE“ nicht primary key, d.h. ein Name kann zig Rufnummern haben. In „TABCHANGE“ sind sie es (d.h. es gibt eine eindeutige letzte Änderung).

Jetzt mein Problem:
Wenn in „TABELLE“ ein neuer Eintrag eingefügt wird, aber jener Name noch nicht existiert, soll per Trigger in „TABCHANGE“ ein neuer Eintrag mit Name und jetzigem Datum angelegt werden.
Wenn jener Name schon existiert, soll in „TABCHANGE“ kein neuer Eintrag entstehen, sondern der bestehende Eintrag für das letzte Änderungsdatum aktualisiert werden.

Im Prinzip habe ich das hier, aber ich kriege einen Fehler beim Ausführen, weil er das Select nicht mag. Was mache ich falsch - und gibt es evtl. eine ganz andere Möglichkeit, um das „If count(*) … = 0“ nicht zu brauchen?

CREATE OR REPLACE TRIGGER MYTRIGGER
BEFORE INSERT OR UPDATE
ON TABELLE
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
BEGIN 
 if INSERTING or UPDATING then 
 if ( select count(\*) from TABCHANGE where NAME= :new.NAME = 0 ) then 
 INSERT INTO TABCHANGE ( NAME, LAST\_MODIFY ) 
 VALUES ( :new.NAME, SYSDATE);
 else 
 UPDATE TABCHANGE 
 where where NAME= :new.NAME
 set LAST\_MODIFY = SYSDATE;
 end if; 
 end if;
END

Danke und Gruss,
Michael

Hallo mike,

die einfachste Lösung wäre in etwa das hier (ungetestet)

CREATE OR REPLACE TRIGGER MYTRIGGER
BEFORE INSERT OR UPDATE
ON TABELLE
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
BEGIN
if INSERTING or UPDATING then

BEGIN

INSERT INTO TABCHANGE ( NAME, LAST_MODIFY )
VALUES ( :new.NAME, SYSDATE);

EXCEPTION WHEN DUP_VAL_ON_INDEX THEN

UPDATE TABCHANGE
where where NAME= :new.NAME
set LAST_MODIFY = SYSDATE;

END;

end if;
END

d.h. du verwendest einfach den Primary Key von TabChange um die richtige Aktion auszuführen, dann bekommst du auch kein Problem mit Concurrency (z.B. indem der neue Satz von einer anderen Session bereits eingefügt aber noch nicht commited wurde - eine beliebte Falle bei Triggern übrigens).

Gruß
Martin

Danke Dir, Martin. Das hat schon mal funktioniert.

die einfachste Lösung wäre in etwa das hier (ungetestet)

d.h. du verwendest einfach den Primary Key von TabChange um die richtige Aktion auszuführen, dann bekommst du auch kein Problem mit Concurrency (z.B. indem der neue Satz von einer anderen Session bereits eingefügt aber noch nicht commited wurde - eine beliebte Falle bei Triggern übrigens).

Jetzt habe ich doch ein Problem mit concurrency…

CREATE OR REPLACE TRIGGER MYSELF
after update of MYCOL on MYTAB
BEGIN
 update MYTAB set MYVAL="1" where MYCOL= :new.MYCOL;
END

Das schluckt er nicht.
Ich meine, er kompiliert den Trigger, aber meckert dann bei Update von MYCOL irgendwas rum, dass der Trigger das Update nicht richtig sieht, und MYVAL wird nicht gesetzt.

Insgesamt eine blöde Idee oder kann man da was tun?

Gruss,
Michael

Hi Mike,

Jetzt habe ich doch ein Problem mit concurrency…

CREATE OR REPLACE TRIGGER MYSELF
after update of MYCOL on MYTAB
BEGIN
update MYTAB set MYVAL=„1“ where MYCOL= :new.MYCOL;
END

Das ist weniger ein Problem mit Concurrency als mit der Logik insgesamt, schätze ich mal.

Das schluckt er nicht.
Ich meine, er kompiliert den Trigger, aber meckert dann bei
Update von MYCOL irgendwas rum, dass der Trigger das Update
nicht richtig sieht, und MYVAL wird nicht gesetzt.

Yepp.

Insgesamt eine blöde Idee

Ebenfalls ja.

oder kann man da was tun?

Was soll denn das Ding tun (also von der Programmlogik her gesehen).

Gruß
Martin

P.S.: Falls dir zum zweiten Problem jemand mit autonomous_transaction kommt: Glaub ihm kein Wort - außer es stört dich nicht, wenn deine Daten logisch korrumpiert werden. Autonomous Transactions sind ausschließlich zum Logging geeignet (und um den unnötigen commit in DBMS_Lock zu umgehen, falls das wer verwendet).

Hallo,

Das ist weniger ein Problem mit Concurrency als mit der Logik insgesamt, schätze ich mal.

Fast wie ich gedacht habe :wink:

Was soll denn das Ding tun (also von der Programmlogik her gesehen).

Prinzipiell geht es darum:
Eine Tabelle A enthält irgendwelche Daten.
Tabelle B enthält im Prinzip eine Art Aktionsprotokoll.
Wenn jetzt Tabelle A geändert wird, wird in Tabelle B ebenjene Änderung mit Art und Datum automatisch nachgehalten.
Ein externer Prozess fragt an, ob in Tabelle B Änderungen vom Typ „Neueintrag“ protokolliert wurden.

Sollte jetzt ein anderer externer Prozess die Daten weiterverarbeiten, wird in Tabelle B die Art der Aktion protokolliert.
Jetzt wollte ich, dass der externe Prozess nur ein Update auf eben seine eigene Spalte (CHANGE_TYPE) in Tabelle B macht, und ein Trigger mir automatisch den Datumswert (CHANGE_DATE) daneben pflanzt.

Nun habe ich, so wie ich das sehe, nur noch die beiden Möglichkeiten:
entweder eine der Spalten in eine andere Tabelle auslagern, oder beide Werte übergeben?
Oder übersehe ich was?

Gruss,
Michael

Hi Michael,

Sollte jetzt ein anderer externer Prozess die Daten
weiterverarbeiten, wird in Tabelle B die Art der Aktion
protokolliert.
Jetzt wollte ich, dass der externe Prozess nur ein Update auf
eben seine eigene Spalte (CHANGE_TYPE) in Tabelle B macht, und
ein Trigger mir automatisch den Datumswert (CHANGE_DATE)
daneben pflanzt.

Sollte ich das richtig sehen, dann brauchst du in etwa diesen hier:

CREATE OR REPLACE TRIGGER myTrig 
 BEFORE UPDATE OF change\_type ON myTab 
 FOR EACH ROW
BEGIN
 :NEW.change\_date := SYSDATE;
END;
/

Ich hoffe das war das, was du brauchst.

Beste Grüße,
Martin