2016-07-14 19 views
1

Ich habe die folgende plpgsql -Funktion definiert (Vor Trigger), um die Daten zu aktualisieren, wenn eine der Spalten zur Verfügung gestellt wird, ich werde die andere aus statischen Daten bekommen. Aber ich möchte wissen, was der beste Weg ist, um die statischen Daten für gegebene "columna" zu bekommen, ich muss die "columnb" von static_tbl bekommen (mehr wie Wörterbuch/map datastrcuture). Im Moment frage ich innerhalb der Trigger-Funktion nach der statischen Tabelle.Der beste Weg, statische Daten vor dem Trigger zu bekommen

Ich weiß, dass ich die Case-Anweisung als Abfrage verwenden kann. Bitte lassen Sie mich wissen, was hier am besten passt. Hinzufügen der Testdaten Say ColumnA enthält 'a' es wird in ColumnB als 'Alphabet A' propagiert Sonst enthält ColumnB 'Alphabet A' und wird als 'a' an ColumnA weitergegeben. Was ist der beste Weg, um die statischen Daten zu speichern, die für die Umwandlung von columnA-Wert in columnB-Wert verwendet werden?

CREATE FUNCTION update_tblname_column_b() RETURNS TRIGGER AS $$ 
     BEGIN                   
     IF NEW IS NULL THEN                
      RAISE EXCEPTION 'this function cannot be installed with a DELETE trigger'; 
    END IF; 
    IF NEW.column_b IS NOT NULL AND NEW.column_a IS NULL THEN 
     NEW.column_a = (select column_a from static_tbl where column_b = NEW.column_b); 
    ELSIF NEW.column_a IS NOT NULL AND NEW.column_b IS NULL THEN 
     NEW.column_b = (select column_b from static_tbl where column_b = NEW.column_a); 
    END IF; 
    RETURN NEW; 
    END; 

$$ LANGUAGE PLPGSQL; 

CREATE TRIGGER populate_column 
          BEFORE INSERT OR UPDATE ON creatives FOR each ROW 
          EXECUTE PROCEDURE update_tblname_column_b(); 
+0

Dies ist unklar. Bitte fügen Sie den Trigger selbst nicht nur die Triggerfunktion hinzu. Bitte fügen Sie Beispieldaten hinzu, was vor und nach dem Auslöser sein sollte. – SMW

+0

@SMW Hinzugefügt die Trigger-Definition selbst und einige Test-Probe der Definition von Trigger – Shankar

Antwort

2

Wenn column_a ist funktional abhängig von column_b (oder umgekehrt), in stabiler Weise die beste Art ist nicht den funktional abhängig Wert überhaupt zu speichern. Schauen Sie es sich im laufenden Betrieb an. Vielleicht erstellen Sie eine Ansicht (oder eine materialisierte Ansicht) zur Vereinfachung. Möglicherweise die referenzielle Integrität mit einer FOREIGN KEY Einschränkung sicherstellen. Integrieren Sie die Suche in Ihre Eingabelogik. Dann brauchen Sie keinen Auslöser.

Wenn Sie tatsächlich beiden Spalten und einen Trigger benötigen, reparieren einen hinterhältig Fehler: Sie erklären Variablencolumn_a und column_b, die überall in dem Funktionskörper sichtbar sind. Wenn Sie die identische Spalte Namen column_a und column_b ohne Tabellenqualifizierung verwenden, produzieren Sie einen Namenskonflikt. Verwandte:

Die Lösung in Ihrem Fall ist einfach: nicht erklären, die Variablen zu beginnen, haben Sie keine Verwendung für sie. Die allgemeine Lösung ist immer Tabellenqualifizierung Spaltennamen, wenn Konflikte möglich sind. Ich implementiert beides:

CREATE OR REPLACE FUNCTION update_tblname_column_b() 
    RETURNS TRIGGER AS $$ 
BEGIN                   
    IF TG_OP = 'DELETE' THEN 
     RAISE EXCEPTION 'This function cannot be used for DELETE trigger.'; 
    END IF; 

IF NEW.column_b IS NOT NULL AND NEW.column_a IS NULL THEN 
    SELECT INTO NEW.column_a s.column_a 
    FROM static_tbl s 
    WHERE s.column_b = NEW.column_b; 

ELSIF NEW.column_a IS NOT NULL AND NEW.column_b IS NULL THEN 
    SELECT INTO NEW.column_b s.column_b 
    FROM static_tbl s 
    WHERE s.column_a = NEW.column_a; 
END IF; 

RETURN NEW; 

END 
$$ LANGUAGE plpgsql; 

Überprüfen Sie auch nicht für NULL den Triggertyp zu identifizieren, kann dies Ecke Fall falsch sein.Überprüfen Sie die spezielle Variable TG_OP statt:


Eine alternative Möglichkeit, Lookup-Werte speichern würde die enum data type sein. Aber ich würde enum für mehr als ein paar Optionen nicht verwenden und nur wenn sie sich kaum ändern. Eigentlich bevorzuge ich Lookup-Tabellen mit FK-Constraints.

+0

Danke für Ihre Kommentare. 1) Ich brauche nicht die column_a, column_b Deklaration, ich habe das selbe aus meiner Frage entfernt 2) Warum kann ich Trigger nicht benutzen? (Antwort: Ja, Sie haben Recht, wir können Views wie erwähnt verwenden, aber in Zukunft werde ich column_b behalten (was eine neue Spalte ist) und deprecate/drop column_a (alte Spalte)) 3) Meine eigentliche Frage ist, ob es anders geht speichern Sie die Nachschlagedaten (ähnlich dem Wörterbuch in Python). Weil ich nur wissen möchte, gibt es bessere Möglichkeiten, die Nachschlagedaten zu speichern. – Shankar

0

Ich denke, Ihre Methode ein Wörterbuch mit einer Tabellenstruktur zu schaffen, wie das funktionieren würde, wenn die else-Klausel nicht ganz Sinn für mich. Meintest Du "WHERE column_a = NEW.column_a"? Wie auch immer, dies könnte sein, etwas einfacher:

CREATE FUNCTION update_tblname_column_b() RETURNS TRIGGER AS $$ 
    DECLARE 
     column_a tblname.column_a%TYPE; 
     column_b tblname.column_b%TYPE; 
    BEGIN                   
     IF NEW IS NULL THEN                
      RAISE EXCEPTION 'this function cannot be installed with a DELETE trigger'; 
    END IF; 

    NEW.column_a = COALESCE(NEW.column_a, (SELECT column_a FROM static_tbl WHERE column_b = NEW.column_b)); 
    NEW.column_b = COALESCE(NEW.column_b, (SELECT column_b FROM static_tbl WHERE column_a = NEW.column_a)); 

    RETURN NEW; 
END; 

$$ LANGUAGE PLPGSQL; 

CREATE TRIGGER populate_column 
    BEFORE INSERT OR UPDATE ON creatives FOR each ROW 
     EXECUTE PROCEDURE update_tblname_column_b(); 

Die COALESCE-Funktion gibt das erste Nicht-Null-Argument in der Liste. Wenn alle Argumente NULL sind, wird NULL zurückgegeben.

Je nachdem, wie Sie dies verwenden möchten, sollten Sie einige der neuen JSON-Funktionen in postgres 9.3 und höher verwenden. Das würde Ihnen eine andere Möglichkeit geben, Schlüssel/Wert-Paare zu erstellen.

+0

Vielen Dank für die Vereinfachung Vorschlag zur Verfügung gestellt :-) Könnten Sie mir einen Verweis für wie dict like Strukturen in Postgres und verwenden Sie das gleiche in PlPgsql Funktion? – Shankar

+0

Es gibt mindestens ein paar Optionen für die Verwendung von Schlüssel/Wert-Paaren in Postgres. Einer ist via Hstore: http://www.postgresqltutorial.com/postgresql-hstore/ Ein weiterer über JSON: http://stormatics.com/howto-use-json-funktionality-in-postgresql/ – tjs

+0

@Shankar: Diese Trigger-Funktion würde aufgrund des (unnötigen) Namenskonflikts einen Fehler erzeugen "Spaltenreferenz" column_a "ist mehrdeutig". Genau wie das Original. Diese Antwort ist tatsächlich dem Original unterlegen und führt SELECTs bedingungslos aus, was eine Verschwendung ist. –