【问题标题】:Using `BEFORE INSERT` trigger to change the datatype of incoming data to match the column datatype in PostgreSQL使用 `BEFORE INSERT` 触发器更改传入数据的数据类型以匹配 PostgreSQL 中的列数据类型
【发布时间】:2016-08-20 15:19:25
【问题描述】:

我有一个 postgres 表,其中有一列 C,其类型为 T。人们将使用COPY 将数据插入此表中。但是有时他们会尝试为 C 插入一个不是 T 类型的值,但是我有一个 postgres 函数可以将值转换为 T。

我正在尝试在表上编写一个BEFORE INSERT 触发器,它将在数据上调用此函数,以便我可以确保没有插入类型错误。但是它似乎不起作用,我在尝试插入数据时遇到错误,即使那里有触发器。

在我花太多时间调查之前,我想知道这是否可能。我可以通过这种方式使用触发器来更改传入数据的类型吗?

我希望它在 postgresql 9.3 上运行,但我注意到 postgres 9.5 上的错误和无效触发器。

【问题讨论】:

  • 我不清楚这是否可行,但你试过rules吗?

标签: database postgresql triggers type-conversion database-trigger


【解决方案1】:

正如 Patrick 所说,您必须指定一个许可目标,以便 Postgres 验证在您有机会操作数据之前不会拒绝数据。

另一种不使用第二个表的方法是在基表上创建一个视图,将所有内容转换为 varchar,然后使用INSTEAD OF 触发器在视图上尝试插入时填充基表。

例如,下面的表 tab1 有一个整数列。视图 v_tab1 有一个 varchar,因此任何插入都适用于该视图。然后,instead of 触发器会检查输入的值是否为数字,如果不是,则使用 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

【讨论】:

    【解决方案2】:

    不,你不能使用这种方法。原因是后端已经用要插入到表中的值填充了一条记录。这是触发器中可用的NEW 参数的形式。因此,即使在触发器触发之前也会引发错误。

    顺便说一句,这同样适用于规则,因此 Kevin 在评论中的建议不会奏效。

    您最好的解决方案可能是创建一个具有“许可”列数据类型(例如 text)的临时表,然后在该表上放置一个 BEFORE INSERT 触发器,在插入之前将所有列值转换为正确的类型在决赛桌。如果第二次插入成功,您甚至可以从插入中RETURN NULL,这样该行就不会进入表中(但不确定COPY 对此有何看法……)。那些最终出现在表中的记录中包含一些奇怪的数据,然后您可以手动处理这些行。

    【讨论】:

      猜你喜欢
      • 2021-07-26
      • 2021-10-31
      • 2012-12-16
      • 2019-11-08
      • 1970-01-01
      • 2019-04-29
      • 2011-11-02
      • 2018-07-08
      相关资源
      最近更新 更多