Ror*_*ory 8 database postgresql triggers type-conversion database-trigger
我有一个postgres表,列C有一个类型T.人们将使用COPY将数据插入此表.但是有时他们会尝试为不属于T类型的C插入一个值,但是我有一个postgres函数可以将值转换为T.
我正在尝试BEFORE INSERT在表上写一个触发器,它将在数据上调用此函数,以便我可以确保没有插入类型错误.然而,它似乎不起作用,我在尝试插入数据时遇到错误,即使触发器在那里.
在我花太多时间调查之前,我想知道这是否可行.我可以以这种方式使用触发器来更改传入数据的类型吗?
我希望这个在postgresql 9.3上运行,但我注意到postgres 9.5上的错误和无效触发器.
不,你不能使用这种方法.原因是后端已经使用要插入表中的值填充记录.这是NEW触发器中可用参数的形式.因此,即使在触发器触发之前,也会抛出错误.
顺便提一下,这同样适用于规则,因此凯文在他的评论中的建议是行不通的.
可能你最好的解决方案是创建一个具有"许可"列数据类型(例如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();
Run Code Online (Sandbox Code Playgroud)
现在无论值如何,插入都可以工作
insert into v_tab1 values ('12','hello');
insert into v_tab1 values ('banana','world');
select * from tab1;
Run Code Online (Sandbox Code Playgroud)
给予
|i1 |v1 |
+-----+-----+
|12 |hello|
|0 |world|
Run Code Online (Sandbox Code Playgroud)
小提琴:http://sqlfiddle.com/#!15/ 9af5ab/1