这是一个实例,我要对一个数据库表的数据创建一个统计缓存,这个统计缓存由于数据量较大,我采用了按年分布表的方式。首先设计了基表,所有的数据分区都是基于这个基表继承而来。为了方便分区和维护,我专门写了一个函数来创建分区子表。
create or replace function stat_partition(stat_year integer) returns void as $BODY$ declare sql character varying; tablename character varying; tblyear character varying; i integer; cur cursor for select p.relname from pg_inherits i,pg_class p where i.inhparent=(select oid from pg_class where relname='base_stat') and p.oid=i.inhrelid order by p.relname; begin tablename='stat_'||cast(stat_year as character varying); --创建表 sql='create table '||tablename|| ' (constraint pk_'||tablename||' primary key (id),'|| ' constraint chk_'||tablename||' check ((from_date>='''||cast(stat_year as character varying)||'-1-1''::date) and (to_date<='''||cast(stat_year+1 as character varying)||'-1-1''::date)))'|| ' inherits (base_stat);'; execute sql; --表注释 sql='comment on table '||tablename|| ' is '''||cast(stat_year as character varying)||' 年统计结果汇总缓存表'';'; execute sql; -- 表索引 -- areacode sql='create index idx_'||tablename||'_areacode on '||tablename||' (areacode);'; execute sql; -- from_age sql='create index idx_'||tablename||'_from_age on '||tablename||' (from_age);'; execute sql; -- to_age sql='create index idx_'||tablename||'_to_age on '||tablename||' (to_age);'; execute sql; -- from_date sql='create index idx_'||tablename||'_from_date on '||tablename||' (from_date);'; execute sql; -- to_date sql='create index idx_'||tablename||'_to_date on '||tablename||' (to_date);'; execute sql; -- illcode sql='create index idx_'||tablename||'_to_illcode on '||tablename||' (illcode);'; execute sql; -- 创建触发器函数 sql='create or replace function tgr_base_stat() returns trigger as $$ '||chr(10)||'begin'||chr(10); open cur; fetch cur into tablename; i=0; while found loop tblyear=right(tablename,4); if i=0 then sql=sql||'if New.from_date>='''||tblyear||'-1-1'' and New.to_date<='''||cast(cast(tblyear as integer)+1 as character varying)||'-1-1'' then '||chr(10)|| 'insert into '||tablename||' values (New.*);'||chr(10); else sql=sql||'elsif New.from_date>='''||tblyear||'-1-1'' and New.to_date<='''||cast(cast(tblyear as integer)+1 as character varying)||'-1-1'' then '||chr(10)|| 'insert into '||tablename||' values (New.*);'||chr(10); end if; i=i+1; fetch cur into tablename; end loop; close cur; sql=sql||'else '||chr(10)||' raise exception ''指定的记录无法自动插入任何一个分区,请检查数据或调用stat_partition(%)建立新的分区。'',extract(year from New.from_date);' ||chr(10)||'end if;'||chr(10)||'return NULL;'||chr(10)|| 'end; $$ language plpgsql;'; execute sql; if not exists (select * from pg_trigger where tgname='stat_insert_redirect') then begin sql='create trigger stat_insert_redirect before insert on base_stat for each row execute procedure tgr_base_stat();'; execute sql; end; end if; end; $BODY$ language plpgsql;
函数主要做了以下事情:
(1)用 create or replace 而不是 create 方便在函数已经存在的时候,直接替换,这就相比MSSQL方便多了。
(2)声明了一个游标来获取从base_stat表继承下来的所有子表,以便自动更新触发器触发时要执行的函数。
(3)首先从父表继承创建了子表,并自动创建了主键和检查约束,以便进行数据分区。
(4)接下来是为表加入注释,并且自动添加需要的索引。
(5)更新触发器函数,以便在插入数据时自动进入新的分区。
(6)如果指定的触发器,则创建触发器,以便建立触发器与执行函数之间的关联。
具体的步骤就不在分析,看得懂的自然看明白了,看不懂了,还是该干嘛干嘛吧。