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.