Использование триггера "перед вставкой" для изменения типа данных входящих данных в соответствии с типом данных столбца в PostgreSQL

у меня есть таблица postgres, со столбцом C, который имеет тип T. Люди будут использовать COPY для вставки данных в эту таблицу. Однако иногда они пытаются вставить значение для C, которое не имеет типа T, однако у меня есть функция postgres, которая может преобразовать значение в T.

Я пытаюсь написать BEFORE INSERT trigger в таблице, которая вызовет эту функцию на данных, чтобы я мог убедиться, что я не получаю ошибок типа вставки. Однако это, похоже, не работает, я получаете ошибки при попытке вставить данные, даже с триггером там.

прежде чем я потрачу слишком много времени на расследование, я хочу выяснить, возможно ли это. Могу ли я использовать триггеры таким образом, чтобы изменить тип входящих данных?

Я хочу, чтобы это работало на postgresql 9.3, но я заметил ошибку и нефункционирующий триггер на postgres 9.5.

2 ответов


нет, вы не можете использовать этот подход. Причина в том, что серверная часть уже заполняет записи со значениями, которые должны быть вставлены в таблицу. Это в форме NEW параметр, доступный в триггере. Таким образом, ошибка возникает еще до срабатывания триггера.

то же самое относится и к правилам, кстати, поэтому предложение Кевина в его комментарии не будет работать.

вероятно, ваше лучшее решение-создать промежуточную таблицу с столбцом " permissive типы данных (например,text), а затем поставить BEFORE INSERT триггер в этой таблице, который приводит все значения столбцов к их правильному типу перед вставкой их в конечную таблицу. Если эта вторая вставка успешна, вы можете даже RETURN NULL из вставки, чтобы строка не входила в таблицу (не уверен, однако, что COPY думает об этом...). Те записи, которые попадают в таблицу, имеют некоторые странные данные, и вы можете обрабатывать эти строки вручную.


как заявил Патрик, вы должны указать разрешительную цель, чтобы проверка Postgres не отклоняла данные, прежде чем вы получите возможность манипулировать ею.

другой способ без второй таблицы-создать представление на вашей базовой таблице, которое бросает все в varchar, а затем имеет INSTEAD OF триггер, который заполняет базовую таблицу при попытке вставки в представлении.

например, таблица tab1 ниже имеет целочисленный столбец. Представление v_tab1 имеет varchar вместо этого любая вставка будет работать для представления. Вместо триггера затем проверяет, является ли введенное значение числовым, а если нет, то использует 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();

теперь вставки будут работать независимо от значения

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

дав

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

Скрипка на: http://sqlfiddle.com/#!15/9af5ab/1