postgresql在分表的情况下,绑定触发器,使某个字段自动更新

要点:
1.postgresql分表需要使用触发器完成,分表后一个主表以及n个子表;
2.给某个字段,如(update_time)设置自动填充,仍需要创建触发器,但是不能光绑定主表,应该给每一个子表都绑定该触发器;
分表触发器代码

CREATE OR REPLACE FUNCTION "public"."auto_insert_sub_indicator_table"()
  RETURNS "pg_catalog"."trigger" AS $BODY$
DECLARE
    admission_date    text ;			-- 父表中用于分区的时间字段的名称(推送时间)	
    curMM               varchar(6);		-- 'YYYYMM'字串,用做分区子表的后缀
    isExist             boolean;		-- 分区子表,是否已存在
    startTime           text;
    endTime             text;
    strSQL              text;
    
-- 如果表名使用很多,也可以声明一个变量表示字表名称
BEGIN
    -- 调用前,必须首先初始化(时间字段名):admission_date [直接从调用参数中获取!!]
    -- 没有显示的声明参数,使用TG_ARGV[0]获取参数
    admission_date := TG_ARGV[0];


    -- 判断对应分区表 是否已经存在?
	EXECUTE 'SELECT $1.'||admission_date INTO strSQL USING NEW;
	curMM := to_char( strSQL::timestamp , 'YYYYMM' );
	select count(*) INTO isExist from pg_class where relname = (TG_TABLE_NAME||'_'||curMM);

	-- 若不存在, 则插入前需先创建子分区
	IF ( isExist = false ) THEN
        -- 创建子分区表,写明约束。TG_TABLE_NAME为主表的名字,分表将继承主表的所有字段,但不会继承主键和索引等,需要手动创建。		
        startTime := left(curMM, 4)||'-'||right(curMM, 2)||'-01 00:00:00';

        endTime := to_char( startTime::timestamp + interval '1 month', 'YYYY-MM-DD HH24:MI:SS');
        strSQL := 'CREATE TABLE IF NOT EXISTS '||'"'||TG_TABLE_NAME||'_'||curMM||'"'||
                  ' ( CHECK('||admission_date||'>='||''''|| startTime||'''' ||' AND '
                             ||admission_date||'< '||''''|| endTime ||''''||' )
                          ) INHERITS ('||'"'||TG_TABLE_NAME||'"'||') ;';
				EXECUTE strSQL;
				-- 创建主键,id主键只能保证单个表的唯一,多个子表可能会存在相同的主键。这里为子表创建复合主键
        strSQL := 'ALTER TABLE '||'"'||TG_RELNAME||'_'||curMM||'"'||' ADD PRIMARY KEY("patient_id","visit_id","section_id","field_id") ';
        EXECUTE strSQL;
        -- 创建索引(使用分表的字段),可选。 TODO: 现在先只为业务数据日期时间添加索引,后面有需要再加
        strSQL := 'CREATE INDEX '||'"'||TG_TABLE_NAME||'_'||curMM||'_INDEX_patient_id'||'"'||' ON '
                          ||'"'||TG_TABLE_NAME||'_'||curMM||'"'||' ("patient_id");';
        EXECUTE strSQL;
				strSQL := 'CREATE INDEX '||'"'||TG_TABLE_NAME||'_'||curMM||'_INDEX_visit_id'||'"'||' ON '
                          ||'"'||TG_TABLE_NAME||'_'||curMM||'"'||' ("visit_id");';
        EXECUTE strSQL;
				strSQL := 'CREATE INDEX '||'"'||TG_TABLE_NAME||'_'||curMM||'_INDEX_field_id'||'"'||' ON '
                          ||'"'||TG_TABLE_NAME||'_'||curMM||'"'||' ("field_id");';
        EXECUTE strSQL;
				strSQL := 'CREATE UNIQUE INDEX '||'"'||TG_TABLE_NAME||'_'||curMM||'_INDEX_unique'||'"'||' ON '
                          ||'"'||TG_TABLE_NAME||'_'||curMM||'"'||' ("patient_id","visit_id","section_id","field_id");';
        EXECUTE strSQL;
    	
    END IF;

    -- 插入数据到子分区(主键冲突时更新数据,否则新增数据)!
    strSQL := 'INSERT INTO '||'"'||TG_TABLE_NAME||'_'||curMM||'"'|| ' SELECT $1.*' ||
              ' on conflict (patient_id, visit_id, section_id, field_id) ' ||
              ' do update set ' ||
              ' patient_id = EXCLUDED.patient_id,' ||
              ' visit_id = EXCLUDED.visit_id,' ||
              ' section_id = EXCLUDED.section_id,' ||
              ' field_id = EXCLUDED.field_id,' ||
              ' field_code = EXCLUDED.field_code,' ||
							' field_value = EXCLUDED.field_value,' ||
							' field_name = EXCLUDED.field_name,' ||
							' update_time = EXCLUDED.update_time,' ||
              ' admission_date = EXCLUDED.admission_date' ;
	EXECUTE strSQL USING NEW;
	RETURN NULL;
	
END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100

其中子表名是不断变化的,即:‘"’||TG_TABLE_NAME||‘_’||curMM||‘"’
只要把自动更新的触发器放到里面就可以了,每创建一个新子表,就为该子表绑定触发器。

CREATE OR REPLACE FUNCTION "public"."auto_insert_sub_indicator_table"()
  RETURNS "pg_catalog"."trigger" AS $BODY$
DECLARE
    admission_date    text ;			-- 父表中用于分区的时间字段的名称(推送时间)	
    curMM               varchar(6);		-- 'YYYYMM'字串,用做分区子表的后缀
    isExist             boolean;		-- 分区子表,是否已存在
    startTime           text;
    endTime             text;
    strSQL              text;
    
-- 如果表名使用很多,也可以声明一个变量表示字表名称
BEGIN
    -- 调用前,必须首先初始化(时间字段名):admission_date [直接从调用参数中获取!!]
    -- 没有显示的声明参数,使用TG_ARGV[0]获取参数
    admission_date := TG_ARGV[0];


    -- 判断对应分区表 是否已经存在?
	EXECUTE 'SELECT $1.'||admission_date INTO strSQL USING NEW;
	curMM := to_char( strSQL::timestamp , 'YYYYMM' );
	select count(*) INTO isExist from pg_class where relname = (TG_TABLE_NAME||'_'||curMM);

	-- 若不存在, 则插入前需先创建子分区
	IF ( isExist = false ) THEN
        -- 创建子分区表,写明约束。TG_TABLE_NAME为主表的名字,分表将继承主表的所有字段,但不会继承主键和索引等,需要手动创建。		
        startTime := left(curMM, 4)||'-'||right(curMM, 2)||'-01 00:00:00';

        endTime := to_char( startTime::timestamp + interval '1 month', 'YYYY-MM-DD HH24:MI:SS');
        strSQL := 'CREATE TABLE IF NOT EXISTS '||'"'||TG_TABLE_NAME||'_'||curMM||'"'||
                  ' ( CHECK('||admission_date||'>='||''''|| startTime||'''' ||' AND '
                             ||admission_date||'< '||''''|| endTime ||''''||' )
                          ) INHERITS ('||'"'||TG_TABLE_NAME||'"'||') ;';
				EXECUTE strSQL;
				-- *************************************
				-- *************************************
				-- *************************************
				-- 为每个分表绑定触发器,自动填充update_time
				strSQL := 'CREATE TRIGGER "auto_update_time" BEFORE UPDATE ON "public".'||'"'||TG_TABLE_NAME||'_'||curMM||'"'||
										'FOR EACH ROW
										EXECUTE PROCEDURE "public"."update_timestamp"();';
				EXECUTE strSQL;
				-- *************************************
				-- *************************************
				-- *************************************
				-- 创建主键,id主键只能保证单个表的唯一,多个子表可能会存在相同的主键。这里为子表创建复合主键
        strSQL := 'ALTER TABLE '||'"'||TG_RELNAME||'_'||curMM||'"'||' ADD PRIMARY KEY("patient_id","visit_id","section_id","field_id") ';
        EXECUTE strSQL;
        -- 创建索引(使用分表的字段),可选。 TODO: 现在先只为业务数据日期时间添加索引,后面有需要再加
        strSQL := 'CREATE INDEX '||'"'||TG_TABLE_NAME||'_'||curMM||'_INDEX_patient_id'||'"'||' ON '
                          ||'"'||TG_TABLE_NAME||'_'||curMM||'"'||' ("patient_id");';
        EXECUTE strSQL;
				strSQL := 'CREATE INDEX '||'"'||TG_TABLE_NAME||'_'||curMM||'_INDEX_visit_id'||'"'||' ON '
                          ||'"'||TG_TABLE_NAME||'_'||curMM||'"'||' ("visit_id");';
        EXECUTE strSQL;
				strSQL := 'CREATE INDEX '||'"'||TG_TABLE_NAME||'_'||curMM||'_INDEX_field_id'||'"'||' ON '
                          ||'"'||TG_TABLE_NAME||'_'||curMM||'"'||' ("field_id");';
        EXECUTE strSQL;
				strSQL := 'CREATE UNIQUE INDEX '||'"'||TG_TABLE_NAME||'_'||curMM||'_INDEX_unique'||'"'||' ON '
                          ||'"'||TG_TABLE_NAME||'_'||curMM||'"'||' ("patient_id","visit_id","section_id","field_id");';
        EXECUTE strSQL;

    END IF;

    -- 插入数据到子分区(主键冲突时更新数据,否则新增数据)!
    strSQL := 'INSERT INTO '||'"'||TG_TABLE_NAME||'_'||curMM||'"'|| ' SELECT $1.*' ||
              ' on conflict (patient_id, visit_id, section_id, field_id) ' ||
              ' do update set ' ||
              ' patient_id = EXCLUDED.patient_id,' ||
              ' visit_id = EXCLUDED.visit_id,' ||
              ' section_id = EXCLUDED.section_id,' ||
              ' field_id = EXCLUDED.field_id,' ||
              ' field_code = EXCLUDED.field_code,' ||
							' field_value = EXCLUDED.field_value,' ||
							' field_name = EXCLUDED.field_name,' ||
							' update_time = EXCLUDED.update_time,' ||
              ' admission_date = EXCLUDED.admission_date' ;
	EXECUTE strSQL USING NEW;
	RETURN NULL;
	
END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值