[oracle xe 11g] Trigger über alle Spalten laufen lassen

tigger7985

Grünschnabel
Hallo,

zum sichern von Änderungen in einer Tabelle, habe ich folgenden Trigger verfasst:

SQL:
create or replace trigger aenderungen_speichern
before insert or update or delete on kunde
for each row
declare
  aktionVal varchar2(10) := '';
  userVal varchar2(120) := '';
begin
  userVal := user || ' (' || SYS_CONTEXT('USERENV','IP_ADDRESS') || ')';

  if UPDATING then
    aktionVal := 'update';
  elsif (:old.kundennr is null) then
    aktionVal := 'insert';
  elsif (:new.kundennr is null) then
    aktionVal := 'delete';
  else
    aktionVal := 'unbekannt';
  end if;

if (:old.geschaeftskunde = -1 or :new.geschaeftskunde = -1) then
    if((:old.vorname <> :new.vorname or :new.vorname is null or :old.vorname is null)
      and not (:new.vorname is null and :old.vorname is null)) then
      insert into aenderungslog (datum, aktion, benutzer, spalte, alterWert, neuerWert)
        values (sysdate, aktionVal, userVal, 'vorname', :old.vorname, :new.vorname);
    end if;
    if((:old.kundennr <> :new.kundennr or :new.kundennr is null or :old.kundennr is null)
       and not (:new.kundennr is null and :old.kundennr is null)) then
      insert into aenderungslog (datum, aktion, benutzer, spalte, alterWert, neuerWert)
        values (sysdate, aktionVal, userVal, 'kundennr', :old.kundennr, :new.kundennr);
    end if;   
    if((:old.nachname <> :new.nachname or :new.nachname is null or :old.nachname is null)
        and not (:new.nachname is null and :old.nachname is null)) then
      insert into aenderungslog (datum, aktion, benutzer, spalte, alterWert, neuerWert)
        values (sysdate, aktionVal, userVal, 'nachname', :old.nachname, :new.nachname);
    end if;   
    if(:old.fuehrerschein <> :new.fuehrerschein or :new.fuehrerschein is null or :old.fuehrerschein is null)
        and not (:new.fuehrerschein is null and :old.fuehrerschein is null)) then
      insert into aenderungslog (datum, aktion, benutzer, spalte, alterWert, neuerWert)
        values (sysdate, aktionVal, userVal, 'fuehrerschein', :old.fuehrerschein, :new.fuehrerschein);
    end if;
    if(:old.adresse <> :new.adresse or :new.adresse is null or :old.adresse is null)
        and not (:new.adresse is null and :old.adresse is null)) then
      insert into aenderungslog (datum, aktion, benutzer, spalte, alterWert, neuerWert)
        values (sysdate, aktionVal, userVal, 'adresse', :old.adresse, :new.adresse);
    end if;
    if(:old.geschaeftskunde <> :new.geschaeftskunde or :new.geschaeftskunde is null or :old.geschaeftskunde is null)
        and not (:new.geschaeftskunde is null and :old.geschaeftskunde is null)) then
      insert into aenderungslog (datum, aktion, benutzer, spalte, alterWert, neuerWert)
        values (sysdate, aktionVal, userVal, 'geschaeftskunde', :old.geschaeftskunde, :new.geschaeftskunde);
    end if;
   if(:old.firma <> :new.firma or :new.firma is null or :old.firma is null)
       and not (:new.firma is null and :old.firma is null)) then
      insert into aenderungslog (datum, aktion, benutzer, spalte, alterWert, neuerWert)
        values (sysdate, aktionVal, userVal, 'firma', :old.firma, :new.firma);
    end if;
    if(:old.rabatt <> :new.rabatt or :new.rabatt is null or :old.rabatt is null)
        and not (:new.rabatt is null and :old.rabatt is null)) then
      insert into aenderungslog (datum, aktion, benutzer, spalte, alterWert, neuerWert)
        values (sysdate, aktionVal, userVal, 'rabatt', :old.rabatt, :new.rabatt);
    end if;   
  end if;
end;
/

Im Prinzip wird für jede Spalte geprüft, ob sich was geändert hat, wenn ja wird der Datensatz gespeichert.

Natürlich wäre es mir jetzt lieber das ganze etwas flexibler zu gestalten, indem ich die Spalten der Tabelle durchgehe und dann die Überprüfung mache.

Meine erster Versuch war:

SQL:
create or replace trigger aenderungen_speichern
before insert or update or delete on kunde
for each row
declare
  aktionVal varchar2(10) := '';
  userVal varchar2(120) := '';
 
  cursor spalten is
    select COLUMN_NAME
    from USER_TAB_COLUMNS
    where table_name = 'KUNDE';
 
begin
  userVal := user || ' (' || SYS_CONTEXT('USERENV','IP_ADDRESS') || ')';

  if UPDATING then
    aktionVal := 'update';
  elsif (:old.kundennr is null) then
    aktionVal := 'insert';
  elsif (:new.kundennr is null) then
    aktionVal := 'delete';
  else
    aktionVal := 'unbekannt';
  end if;

if (:old.geschaeftskunde = -1 or :new.geschaeftskunde = -1) then
    for spalte in spalten loop
      if((:old.(spalte.COLUMN_NAME) <> :new.(spalte.COLUMN_NAME) or :new.(spalte.COLUMN_NAME) is null or :old.(spalte.COLUMN_NAME) is null)
        and not (:new.(spalte.COLUMN_NAME) is null and :old.(spalte.COLUMN_NAME) is null)) then
        insert into aenderungslog (datum, aktion, benutzer, spalte, alterWert, neuerWert)
          values (sysdate, aktionVal, userVal, spalte.COLUMN_NAME, :old.(spalte.COLUMN_NAME), :new.(spalte.COLUMN_NAME));
      end if; 
    end loop;
  end if;

end;
/

Klappt aber nicht, weil er die "old" und "new" Werte dann nicht mehr findet.

Hat vielleicht jemand eine Idee wie es trotzdem klappen kann?
 

Neue Beiträge

Zurück