2017-05-22 6 views
0

Ich setze eine Funktion für einen Trigger ausgelöst, wenn ich in Tabelle A einfügen, die ich zuerst einen Eintrag in TabelleB erstellen würde, und erstellen Sie dann einige andere Einträge in der Tabelle C, in denen es einen Fremdschlüssel gibt bezogen auf TabelleB. Aber ich erhalte einen Fehler, da es versucht, in Tabelle C einen Wert in das Fremdschlüsselfeld einzufügen, der in der Tabelle nicht vorhanden ist, solange die Funktion nicht beendet wurde.Sequencing Ergebnisse in Funktion PostgreSQL 9.5

Gibt es einen Weg, der innerhalb einer Funktion eine Art Rückkehr in meine Funktion bringt, die aber die Funktion nicht verlassen und dann den Rest ausführen würde? Etwas, was würde wie folgt aussehen:

CREATE OR REPLACE FUNCTION trigger1() RETURNS trigger AS 
$BODY$ 
begin 
insert into tableB values (new.value); 
RETURN NEW; 
insert into tableC (id, fkey) values (new.something, new.value); 
RETURN NEW; 
end; 
$BODY$ 
LANGUAGE plpgsql; 

Ich habe versucht, die Funktion in zwei verschiedene Trigger zu trennen, in der alphabetischen Reihenfolge der Ausführung zu bestellen, aber ohne Erfolg, vielleicht, weil sie beide laufen, bevor ...

Irgendeine Idee?

Dank

Antwort

2

Deklarieren Sie die Fremdschlüssel in TableC als DEFERRABLE INITIALLY DEFERRED.

Von the documentation:

DEFERRABLE NICHT

DEFERRABLE Diese kontrolliert, ob die Beschränkung aufgeschoben werden kann. Eine Beschränkung, die nicht aufschiebbar ist, wird unmittelbar nach jedem Befehl überprüft. Die Überprüfung von Einschränkungen, die aufgeschoben werden können, kann bis zum Ende der Transaktion (mit dem Befehl SET CONSTRAINTS) auf verschoben werden. NICHT DEFERRABLE ist die Standardeinstellung. Zur Zeit akzeptieren nur die Bedingungen UNIQUE, PRIMARY KEY, EXCLUDE und REFERENCES (Fremdschlüssel) diese Klausel. Die Bedingungen NOT NULL und CHECK sind nicht aufschiebbar.

Btw. die erste RETURN NEW; im Funktionskörper macht keinen Sinn.

+0

Dank. Ich habe Probleme zu verstehen, wie das funktioniert. Was passiert, wenn ich den Fremdschlüssel aufschiebe und der CONSTRAINT nicht eingehalten wird? Wird es einen Fehler verursachen? Am Ende der Transaktion wird es sich also an die gesamte Transaktion "erinnern" und diese stornieren? –

+1

Ja, bei einem Constraint-Fehler wird ein Fehler ausgelöst und die Transaktion wird zurückgesetzt. Sie müssen jedoch keine explizite Transaktion verwenden. Wenn Sie keine äußere Transaktion haben, ist die Trigger-Funktion selbst eine einzelne Transaktion. Im Allgemeinen funktioniert es wie erwartet, ohne dass etwas in einem Trigger geändert werden muss. – klin

2

Erstens ist es unmöglich, zwei RETURN Anweisungen im gleichen Ablauf einer Funktion zu haben.

Über Ihr Problem gibt es viele Möglichkeiten, dies zu erreichen. Eine davon verwendet eine DEFERRABLE TRIGGER (eine spezielle Art von Trigger am Ende der Transaktion ausgewertet). Etwas wie:

--Trigger function 
CREATE OR REPLACE FUNCTION trigger1() RETURNS trigger AS 
$BODY$ 
BEGIN 
    INSERT INTO "tableB" VALUES (new.value); 
    INSERT INTO "tableC" (id, fkey) VALUES (new.something, new.value); 
    RETURN NEW; 
END; 
$BODY$ 
LANGUAGE plpgsql; 

--Trigger raised at end of transaction. Take a look on 'CONSTRAINT' and 'INITIALLY DEFERRED' clauses. 
CREATE CONSTRAINT TRIGGER deferred_trigger_1 
    AFTER INSERT OR UPDATE 
    ON "tableA" 
    INITIALLY DEFERRED 
    FOR EACH ROW 
    EXECUTE PROCEDURE trigger1(); 

Mehr Infos here

+0

Danke. Ich kann jedoch nicht finden, wie diese DEFERRABLE TRIGGER funktioniert. Könnten Sie mir ein Beispiel für die Syntax für diese Art von Auslösern geben? –

+0

@GuiOmClair Siehe meine aktualisierte Antwort. –

Verwandte Themen