6

Mam tabelę postgres z kolumną C, która ma typ T. Użytkownicy będą używać COPY do wstawiania danych do tej tabeli. Jednak czasami próbują wstawić wartość C, która nie jest typu T, jednak mam funkcję postgres, która może przekonwertować wartość na T.Użycie wyzwalacza `PRZED WSTAWIĆ` do zmiany typu danych przychodzących w celu dopasowania do typu danych kolumny w PostgreSQL

Próbuję napisać wyzwalacz BEFORE INSERT na stole, który będzie wywołaj tę funkcję na danych, aby upewnić się, że nie otrzymuję błędów typu wkładki. Jednak nie wydaje się działać, otrzymuję błędy podczas próby wstawienia danych, nawet z wyzwalaczem tam.

Zanim spędzę zbyt wiele czasu na badaniu, chcę się dowiedzieć, czy jest to możliwe. Czy mogę używać wyzwalaczy w ten sposób do zmiany typu przychodzących danych?

Chcę, aby to działało na PostgreSQL 9.3, ale zauważyłem błąd i nie działający wyzwalacz na PostgreSQL 9.5.

+0

To nie jest dla mnie jasne, czy to będzie działać, ale mają próbowałeś [rules] (http://www.postgresql.org/docs/current/static/rules.html)? – Kevin

Odpowiedz

4

Nie, nie można zastosować tego podejścia. Powodem jest to, że backend zapełnia już rekord wartościami, które mają zostać wstawione do tabeli. Jest to w postaci parametru NEW dostępnego w wyzwalaczu. Tak więc błąd jest zgłaszany nawet przed uruchomieniem wyzwalacza.

To samo dotyczy zasad, nawiasem mówiąc, więc sugestia Kevina w jego komentarzu nie zadziała.

Prawdopodobnie najlepszym rozwiązaniem jest utworzenie tabeli pomostowej z "dozwolonymi" typami danych kolumn (takimi jak text), a następnie wstawienie do tego stołu wyzwalacza BEFORE INSERT, który rzuca wszystkie wartości kolumn do ich poprawnego typu przed wstawieniem ich do ostatecznego stół. Jeśli to drugie wstawienie zakończy się powodzeniem, możesz nawet RETURN NULL wstawić z wkładki, aby rząd nie wszedł do stołu (nie wiesz jednak, co o tym myśli COPY ...). Te rekordy, które kończą się w tabeli, zawierają w sobie dziwne dane, a następnie możesz ręcznie zająć się tymi wierszami.

5

Jak stwierdził Patrick, musisz określić dopuszczalny cel, aby walidacja Postgreatora nie odrzuciła danych, zanim uzyskasz szansę manipulowania nim.

Innym sposobem bez drugiej tabeli jest utworzenie widoku na stole bazowym, który rzuca wszystko na varchar, a następnie wyzwalacz INSTEAD OF wypełnia tabelę podstawową za każdym razem, gdy próbka zostanie wypróbowana w widoku.

Na przykład poniższa tabela tab1 zawiera kolumnę całkowitą. Widok v_tab1 ma varchar zamiast tego, więc każdy insert będzie działał dla widoku. Zamiast wyzwalacza sprawdza, czy wprowadzona wartość ma wartość numeryczną, a jeśli nie, to zamiast tego używa wartości 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(); 

Teraz wkładki będzie działać niezależnie od wartości

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

Nadanie

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

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