6

Ich habe eine Postgres-Tabelle, mit einer Spalte C, die T Typ hat. Personen werden COPY verwenden, um Daten in diese Tabelle einzufügen. Manchmal versuchen sie jedoch, einen Wert für C einzufügen, der nicht vom Typ T ist, aber ich habe eine Postgres-Funktion, die den Wert in T umwandeln kann.Trigger `BEFORE INSERT` verwenden, um den Datentyp der eingehenden Daten zu ändern, um den Spalten-Datentyp in PostgreSQL

Ich versuche, einen BEFORE INSERT Trigger auf der Tabelle zu schreiben, der wird Rufen Sie diese Funktion auf den Daten auf, damit ich sicherstellen kann, dass ich keine Fehler vom Einfügetyp erhalte. Es scheint jedoch nicht zu funktionieren, ich bekomme Fehler, wenn ich versuche, die Daten einzufügen, sogar mit dem Trigger dort.

Bevor ich zu viel Zeit mit der Untersuchung verbringe, möchte ich herausfinden, ob das möglich ist. Kann ich auf diese Weise Auslöser verwenden, um die Art der eingehenden Daten zu ändern?

Ich möchte dies auf PostgreSQL 9.3 laufen, aber ich habe den Fehler und nicht funktionierende Trigger auf Postgre 9.5.

+0

Es mir nicht klar, ob dies funktionieren wird, aber haben Sie haben versucht [Regeln] (http://www.postgresql.org/docs/current/static/rules.html)? – Kevin

Antwort

4

Nein, Sie können diesen Ansatz nicht verwenden. Der Grund dafür ist, dass das Backend bereits einen Datensatz mit den Werten füllt, die in die Tabelle eingefügt werden sollen. Dies ist in Form des Parameters NEW, der im Trigger verfügbar ist. Der Fehler wird also ausgelöst, noch bevor der Auslöser ausgelöst wird.

Das gleiche gilt übrigens für Regeln, so Kevins Vorschlag in seinem Kommentar wird nicht funktionieren.

Wahrscheinlich ist Ihre beste Lösung, eine Zwischenspeichertabelle mit "permissiven" Spaltendatentypen (wie text) zu erstellen und dann einen BEFORE INSERT Trigger auf diese Tabelle zu setzen, der alle Spaltenwerte auf ihren korrekten Typ vor dem Einfügen in das Finale überträgt Tabelle. Wenn diese zweite Einfügung erfolgreich ist, können Sie sogar RETURN NULL aus der Einfügung, so dass die Zeile nicht in die Tabelle gehen (nicht sicher, was, COPY darüber nachdenkt ...). Die Datensätze, die in der Tabelle landen, enthalten einige seltsame Daten und Sie können diese Zeilen dann manuell behandeln.

5

Wie Patrick sagte, müssen Sie ein permissives Ziel angeben, damit die Postgres-Validierung die Daten nicht zurückweist, bevor Sie die Möglichkeit haben, sie zu manipulieren. Ein anderer Weg ohne eine zweite Tabelle besteht darin, eine Sicht auf Ihre Basistabelle zu erstellen, die alles nach varchar umsetzt und dann einen INSTEAD OF Trigger hat, der die Basistabelle auffüllt, wenn ein Insert in der Sicht versucht wird.

Zum Beispiel hat die Tabelle tab1 unten eine ganzzahlige Spalte. Die Ansicht v_tab1 hat stattdessen ein varchar, sodass jede Einfügung für die Ansicht funktioniert. Der Trigger prüft dann, ob der eingegebene Wert numerisch ist und verwendet stattdessen 0.

create table tab1 (i1 int, v1 varchar); 

create view v_tab1 as select cast(i1 as varchar) i1, v1 from tab1; 

create or replace function v_tab1_insert_trgfun() returns trigger as 
$$ 
declare 
    safe_i1 int; 
begin 
    if new.i1 ~ '^([0-9]+)$' then 
    safe_i1 = new.i1::int; 
    else 
    safe_i1 = 0; 
    end if; 

    insert into tab1 (i1, v1) values (safe_i1, new.v1); 
    return new; 
end; 
$$ 
language plpgsql; 

create trigger v_tab1_insert_trigger instead of insert on v_tab1 for each row execute procedure v_tab1_insert_trgfun(); 

Jetzt werden die Einsätze arbeiten unabhängig von dem Wert

insert into v_tab1 values ('12','hello'); 
insert into v_tab1 values ('banana','world'); 
select * from tab1; 

Geben

|i1 |v1 | 
+-----+-----+ 
|12 |hello| 
|0 |world| 

Fiddle an: http://sqlfiddle.com/#!15/9af5ab/1

Verwandte Themen