pg中我们可以通过create rule的方式来实现将入库的数据实时转换成另一种格式,例如我们要存入json类型数据,可以直接存JSON,也可以存格式化数据,甚至可以在导入时,自动将JSON转成结构化数据。那么我们就可以使用实时数据转换的方式。
但是rule的方式有一点不足,对于通过copy协议插入的数据无法做到实时转换,那我们该怎么办呢?通过pg中的触发器不失为一种好的方法。
例子:
1、rule转换
–创建原表
postgis=# create table tt1(id int, c1 numeric, c2 numeric);
CREATE TABLE
–创建目标表
postgis=# create table tt2(id int,geo geometry);
CREATE TABLE
下面创建规则,用来实现将插入tt1的数据c1,c2转换成tt2的geo列的point的横纵坐标。
–创建规则
postgis=# create rule r1 as on insert to tt1 do instead insert into tt2 values (NEW.id,
postgis(# ST_MakePoint(NEW.c1,NEW.c2));
CREATE RULE
–插入数据
postgis=# insert into tt1 values(1,1,1);
INSERT 0 1
–查看
可以发现表tt1中没有数据,数据插入到表tt2中了
postgis=# select * from tt1;
id | c1 | c2
----+----+----
(0 rows)
postgis=# select id,st_astext(geo) from tt2;
id | st_astext
----+------------
1 | POINT(1 1)
(1 row)
2、rule转换json数据
–创建原表
bill=# create table t1 (id int, info text, j jsonb);
CREATE TABLE
–目标表
bill=# create table t2 (id int, info text, c1 int, c2 int, c3 text);
CREATE TABLE
–在源表创建规则,自动将JSONB非结构化数据,转换为结构化数据插入
bill=# create rule r1 as on insert to t1 do instead insert into t2 values (NEW.ID, NEW.INFO, ((NEW.J)->>'c1')::int, ((NEW.j)->>'c2')::int, (NEW.j)->>'c3');
CREATE RULE
–插入数据测试
bill=# insert into t1 values (1,'test',jsonb '{"c1":1, "c2":2, "c3":"text"}');
INSERT 0 1
bill=# select * from t1;
id | info | j
----+------+---
(0 rows)
bill=# select * from t2;
id | info | c1 | c2 | c3
----+------+----+----+------
1 | test | 1 | 2 | text
(1 row)
–copy命令测试,可以发现copy不会触发rule
bill=# copy (select 1,'test',jsonb '{"c1":1, "c2":2, "c3":"text"}') to '/home/pg12/test';
COPY 1
bill=# copy t1 from '/home/pg12/test';
COPY 1
bill=# select * from t1;
id | info | j
----+------+----------------------------------
1 | test | {"c1": 1, "c2": 2, "c3": "text"}
(1 row)
bill=# select * from t2;
id | info | c1 | c2 | c3
----+------+----+----+------
1 | test | 1 | 2 | text
(1 row)
3、trigger转换
–删除rule
bill=# drop rule r1 on t1;
DROP RULE
–创建触发器函数
bill=# create or replace function tg() returns trigger as $$
bill$# declare
bill$# begin
bill$# insert into t2 values (NEW.ID, NEW.INFO, ((NEW.J)->>'c1')::int, ((NEW.j)->>'c2')::int, (NEW.j)->>'c3');
bill$# return null;
bill$# end;
bill$# $$ language plpgsql strict;
CREATE FUNCTION
–创建触发器
bill=# create trigger tg before insert on t1 for each row execute procedure tg();
CREATE TRIGGER
–重新测试
可以发现insert和copy都将数据转换插入到目标表中了。
bill=# truncate t1;
TRUNCATE TABLE
bill=# truncate t2;
TRUNCATE TABLE
bill=# copy t1 from '/home/pg12/test';
COPY 0
bill=# insert into t1 values (1,'test',jsonb '{"c1":1, "c2":2, "c3":"text"}');
INSERT 0 0
bill=# select * from t2;
id | info | c1 | c2 | c3
----+------+----+----+------
1 | test | 1 | 2 | text
1 | test | 1 | 2 | text
(2 rows)
bill=# select * from t1;
id | info | j
----+------+---
(0 rows)
总结:
对于数据的实时转换:如果不需要支持COPY,用rule就可以了。如果需要支持copy和insert, 则需要使用触发器。