Du hast eine schöne View gebaut, die Daten aus drei Tabellen zusammenführt – und dann kommt jemand und will darauf ein INSERT machen. Oracle sagt Nein. Du sagst: Kenn ich ein Mittel.
Willkommen in der Welt der Instead-Of Trigger.


Das Problem: Views sind standardmäßig schreibgeschützt

Wer schon länger mit Oracle arbeitet, kennt das Szenario: Du erstellst eine View, die mehrere Tabellen per JOIN verknüpft, aggregiert oder transformiert – und plötzlich möchte eine Anwendung nicht nur lesen, sondern auch schreiben. Oracle blockiert das mit einem unmissverständlichen Fehler:

-- Versuch, in eine Join-View zu schreiben:
INSERT INTO v_mitarbeiter_abteilung (name, abteilung_name)
VALUES ('Max Müller', 'IT');

-- Oracle antwortet:
ORA-01779: cannot modify a column which maps to a non key-preserved table

Klar, das macht technisch Sinn: Oracle weiß nicht, in welche der zugrunde liegenden Tabellen die Daten sollen. Aber genau hier kommen Instead-Of Trigger ins Spiel – sie sagen Oracle: „Lass mich das übernehmen.“

Was ist ein Instead-Of Trigger?

Ein Instead-Of Trigger ist ein spezieller PL/SQL-Trigger, der anstelle der eigentlichen DML-Operation (INSERT, UPDATE, DELETE) auf einer View ausgeführt wird. Er fängt den Schreibversuch ab – und du entscheidest im Trigger-Body, was wirklich passiert.

Kurz gesagt: Statt Oracle die DML-Operation auf der View ausführen zu lassen (was es sowieso verweigert), springt dein Trigger ein und verteilt die Daten selbst auf die richtigen Basistabellen.

Ein konkretes Beispiel

Nehmen wir ein klassisches Setup: Mitarbeiter und Abteilungen in separaten Tabellen, eine View, die beides zusammenführt.

-- Basistabellen
CREATE TABLE abteilungen (
  abt_id    NUMBER PRIMARY KEY,
  abt_name  VARCHAR2(100)
);

CREATE TABLE mitarbeiter (
  ma_id     NUMBER PRIMARY KEY,
  ma_name   VARCHAR2(100),
  abt_id    NUMBER REFERENCES abteilungen(abt_id)
);

-- Die View - lesbar, aber nicht ohne Weiteres schreibbar
CREATE OR REPLACE VIEW v_mitarbeiter AS
  SELECT m.ma_id, m.ma_name, a.abt_id, a.abt_name
  FROM   mitarbeiter m
  JOIN   abteilungen a ON m.abt_id = a.abt_id;

Jetzt der Trigger. Wir wollen ermöglichen, dass man über die View neue Mitarbeiter anlegen kann:

CREATE OR REPLACE TRIGGER trg_v_mitarbeiter_ins
INSTEAD OF INSERT ON v_mitarbeiter
FOR EACH ROW
DECLARE
  l_abt_id  abteilungen.abt_id%TYPE;
BEGIN
  -- Prüfen ob Abteilung schon existiert
  BEGIN
    SELECT abt_id INTO l_abt_id
    FROM   abteilungen
    WHERE  abt_name = :NEW.abt_name;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      -- Neue Abteilung anlegen
      l_abt_id := abt_seq.NEXTVAL;
      INSERT INTO abteilungen (abt_id, abt_name)
      VALUES (l_abt_id, :NEW.abt_name);
  END;

  -- Mitarbeiter einfügen
  INSERT INTO mitarbeiter (ma_id, ma_name, abt_id)
  VALUES (:NEW.ma_id, :NEW.ma_name, l_abt_id);

END;
/

Ab jetzt funktioniert das INSERT über die View reibungslos:

-- Das klappt jetzt problemlos!
INSERT INTO v_mitarbeiter (ma_id, ma_name, abt_name)
VALUES (42, 'Anna Schmidt', 'IT');

-- Oracle meldet: 1 row created.

UPDATE und DELETE ebenfalls möglich

Natürlich kannst du für alle drei DML-Operationen eigene Instead-Of Trigger anlegen – oder alles in einem Trigger kombinieren:

CREATE OR REPLACE TRIGGER trg_v_mitarbeiter
INSTEAD OF INSERT OR UPDATE OR DELETE ON v_mitarbeiter
FOR EACH ROW
BEGIN

  IF INSERTING THEN
    -- Insert-Logik (wie oben)
    NULL;

  ELSIF UPDATING THEN
    -- Nur den Mitarbeiternamen anpassen
    UPDATE mitarbeiter
    SET   ma_name = :NEW.ma_name
    WHERE ma_id   = :OLD.ma_id;

  ELSIF DELETING THEN
    -- Mitarbeiter löschen (Abteilung bleibt)
    DELETE FROM mitarbeiter
    WHERE ma_id = :OLD.ma_id;

  END IF;

END;
/

Typische Anwendungsfälle

  • Join-Views schreibbar machen – Daten aus mehreren Tabellen über eine View einfügen oder ändern. Der Klassiker.
  • Security-Layer – Nur bestimmte Spalten über die View beschreibbar lassen, andere implizit sperren.
  • Daten-Transformation – Eingehende Werte vor dem Schreiben umrechnen, validieren oder mit Standardwerten anreichern.
  • Auditierung – Jeden Schreibzugriff zentral protokollieren, egal woher er kommt.
  • Object Views – Der einzige Weg, Views auf Basis von Oracle-Objekttypen beschreibbar zu machen.

Was du beachten solltest

Kein Statement-Level: Instead-Of Trigger feuern immer FOR EACH ROW. Eine statement-level Variante gibt es nicht – auch wenn du das FOR EACH ROW weglässt, verhält sich Oracle so, als wäre es angegeben.

💡 Tipp: Du kannst mehrere Instead-Of Trigger auf derselben View kombinieren (z. B. getrennte Trigger für INSERT und DELETE). Oracle führt sie in der Reihenfolge ihrer Erstellung aus.

Außerdem solltest du im Hinterkopf behalten: Je komplexer die Logik im Trigger, desto mehr wird Fehlersuche zur Detektivarbeit. Halte die Trigger-Bodies so schlank wie möglich und lagere komplexe Logik in Packages aus.

Fazit

Instead-Of Trigger sind eines dieser Oracle-Features, das du entweder kennst und liebst – oder das dir irgendwann aus einer verzwickten Situation hilft und ab dann nicht mehr aus deinem Werkzeugkasten wegzudenken ist. Sie machen Views schreibbar, ohne die Kapselung zu opfern, und geben dir vollständige Kontrolle darüber, was bei einem Schreibzugriff auf eine View wirklich passiert.

Gerade in Anwendungen, die ihre Datenbankschicht hinter Views verstecken (aus gutem Grund!), sind
Instead-Of Trigger das Bindeglied, das die Abstraktion vollständig macht.