PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Innerhalb einer Triggerfunktion, wie man herausbekommt, welche Felder aktualisiert werden

Wenn eine "Quelle" keine Kennung "sendet", bleibt die Spalte unverändert. Dann können Sie nicht erkennen, ob das aktuelle UPDATE wurde von der gleichen Quelle wie die letzte gemacht oder von einer Quelle, die die Spalte überhaupt nicht verändert hat. Mit anderen Worten:Das funktioniert nicht richtig.

Wenn die „Quelle“ durch irgendeine Sitzungsinformationsfunktion identifizierbar ist, können Sie damit arbeiten. Wie:

NEW.column = session_user;

Unbedingt bei jedem Update.

Allgemeine Lösung

Ich habe einen Weg gefunden, wie ich das ursprüngliche Problem lösen kann. Die Spalte wird auf einen Standardwert in beliebig gesetzt update, wo die Spalte nicht aktualisiert ist (nicht im SET Liste des UPDATE ).

Schlüsselelement ist ein Trigger pro Spalte eingeführt in PostgreSQL 9.0 - ein spaltenspezifischer Trigger, der das UPDATE OF verwendet column_name Klausel.

Der Trigger wird nur ausgelöst, wenn mindestens eine der aufgelisteten Spalten als Ziel des UPDATE erwähnt wird Befehl.

Das ist die einzige einfache Möglichkeit, die ich gefunden habe, um zu unterscheiden, ob eine Spalte mit einem neuen Wert aktualisiert wurde, der mit dem alten identisch ist, oder ob sie überhaupt nicht aktualisiert wurde.

Man könnte auch den von current_query() zurückgegebenen Text parsen . Aber das scheint schwierig und unzuverlässig.

Triggerfunktionen

Ich gehe von einer Spalte col aus definiert NOT NULL .

Schritt 1: Setzen Sie col auf NULL falls unverändert:

CREATE OR REPLACE FUNCTION trg_tbl_upbef_step1()
  RETURNS trigger AS
$func$
BEGIN
   IF OLD.col = NEW.col THEN
      NEW.col := NULL;      -- "impossible" value
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Schritt 2: Auf alten Wert zurücksetzen. Der Trigger wird nur ausgelöst, wenn der Wert tatsächlich aktualisiert wurde (siehe unten):

CREATE OR REPLACE FUNCTION trg_tbl_upbef_step2()
  RETURNS trigger AS
$func$
BEGIN
   IF NEW.col IS NULL THEN
      NEW.col := OLD.col;
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Schritt 3: Jetzt können wir das fehlende Update identifizieren und stattdessen einen Standardwert setzen:

CREATE OR REPLACE FUNCTION trg_tbl_upbef_step3()
  RETURNS trigger AS
$func$
BEGIN
   IF NEW.col IS NULL THEN
      NEW.col := 'default value';
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Auslöser

Der Auslöser für Schritt 2 wird pro Spalte gefeuert!

CREATE TRIGGER upbef_step1
  BEFORE UPDATE ON tbl
  FOR EACH ROW
  EXECUTE PROCEDURE trg_tbl_upbef_step1();

CREATE TRIGGER upbef_step2
  BEFORE UPDATE OF col ON tbl                -- key element!
  FOR EACH ROW
  EXECUTE PROCEDURE trg_tbl_upbef_step2();

CREATE TRIGGER upbef_step3
  BEFORE UPDATE ON tbl
  FOR EACH ROW
  EXECUTE PROCEDURE trg_tbl_upbef_step3();

Trigger-Namen sind relevant, weil sie in alphabetischer Reihenfolge ausgelöst werden (alle sind BEFORE UPDATE )!

Das Verfahren könnte mit so etwas wie "Pro-Nicht-Spalten-Triggern" oder einer anderen Möglichkeit vereinfacht werden, die Zielliste eines UPDATE zu überprüfen in einem Auslöser. Aber ich sehe keinen Griff dafür.

Wenn col kann NULL sein , verwenden Sie einen anderen "unmöglichen" Zwischenwert und prüfen Sie auf NULL zusätzlich in Triggerfunktion 1:

IF OLD.col IS NOT DISTINCT FROM NEW.col THEN
    NEW.col := '#impossible_value#';
END IF;

Passen Sie den Rest entsprechend an.