PGSQL实现拉链表的存储过程

PGSQL实现拉链表的存储过程

1、表必须有唯一主键,否则拉链不成功
2、函数传入两个参数,第一个参数为表名,第二个参数为主键名
3、过程中会产生两个中间表,不可删除或修改
4、编码不易,记得点赞收藏,如有疑问可以联系本人
请添加图片描述

CREATE OR REPLACE FUNCTION "public"."incre_data"("original_table_name" varchar, "main_key" varchar)
  RETURNS "pg_catalog"."void" AS $BODY$

DECLARE
    marge_data_records_cursor      refcursor;
    marge_data_record              record;
    target_table_records_has_data  BOOLEAN; --目标表记录
    all_column_cursor cursor for SELECT column_name
                                 FROM information_schema.columns
                                 WHERE table_schema = 'public'
                                   AND table_name = original_table_name;
    all_column_name                varchar; -- 所有列字段名,逗号分隔
    all_column_name_array          varchar[];
    now_column_name                VARCHAR; -- 游标操作变量
    main_table_all_column_name     VARCHAR;
    main_table_all_column_array    VARCHAR[];
    origin_table_all_column_name   VARCHAR;
    origin_table_all_column_array  VARCHAR[];
    compare_table_all_column_name  VARCHAR;
    compare_table_all_column_array VARCHAR[];
    all_column_count               int; --原表数据项
    MAX_TIME_DATE                  timestamp := '9999-12-31 00:00:00'; --拉链表默认最大时间
    NOW_TIME_DATE                  timestamp := now(); --当前时间
BEGIN
    execute format(
            'SELECT count(*) FROM information_schema.columns WHERE table_schema = ''public'' AND table_name = ''%I''',
            original_table_name) into all_column_count;
    OPEN all_column_cursor;
    loop
        FETCH all_column_cursor INTO now_column_name;
        -- 对每条记录进行处理
        all_column_name_array := array_append(all_column_name_array, concat('"', now_column_name, '"'));
        main_table_all_column_array := array_append(main_table_all_column_array, concat('AA."', now_column_name, '"'));
        origin_table_all_column_array :=
                array_append(origin_table_all_column_array, concat('BB."', now_column_name, '"'));
        compare_table_all_column_array := array_append(compare_table_all_column_array,
                                                       concat('AA."', now_column_name, '"!=BB."', now_column_name, '"'));
        all_column_count = all_column_count - 1;
        if all_column_count = 0 then exit; end if;
    end loop;
    CLOSE all_column_cursor;
    --所有列名变量
    all_column_name = array_to_string(all_column_name_array, ',');
    main_table_all_column_name = array_to_string(main_table_all_column_array, ',');
    origin_table_all_column_name = array_to_string(origin_table_all_column_array, ',');
    compare_table_all_column_name = array_to_string(compare_table_all_column_array, ' or ');
    if (select count(*) from information_schema.tables where table_name = concat(original_table_name, '_incre')) =
       0 then
        --拉链表不存在,创建新拉链表,复制原来表结构
        EXECUTE format('CREATE TABLE %I_incre AS TABLE %I WITH NO DATA', original_table_name, original_table_name);
        --增加时间起止字段
        execute format(
                'ALTER TABLE "public"."%I_incre" ADD COLUMN "start_time" timestamp,ADD COLUMN "end_time" timestamp',
                original_table_name);
        EXECUTE format('CREATE TABLE %I_incre_marge_temp AS TABLE %I_incre WITH NO DATA', original_table_name,
                       original_table_name);
        EXECUTE format('CREATE TABLE %I_temp AS TABLE %I_incre WITH NO DATA', original_table_name,
                       original_table_name);
        execute format(
                'insert into %I_incre(%s,start_time,end_time) select %s,now() as start_time,to_timestamp(''9999-12-31 00:00:00'',''YYYY-MM-DD  HH24:MI:SS'') as end_time from %I',
                original_table_name, all_column_name, all_column_name, original_table_name);
    else
        --表存在,执行后续拉链操作
        EXECUTE format('SELECT EXISTS (SELECT 1 FROM %I_incre LIMIT 1)',
                       original_table_name) into target_table_records_has_data;
        IF target_table_records_has_data THEN
            --执行具体拉链操作
            --1、删除数据,插入临时表
            EXECUTE format('insert into %I_temp SELECT %s,start_time,''%s'' as end_time ' ||
                           'from (SELECT %s,start_time,end_time from  %I_incre ' ||
                           'WHERE end_time=''%s'') AA ' ||
                           'WHERE not exists ( SELECT 1 FROM %I BB WHERE AA.%s = BB.%s)',
                           original_table_name, all_column_name, NOW_TIME_DATE, all_column_name, original_table_name,
                           MAX_TIME_DATE, original_table_name, main_key, main_key);

            -- 2、新增数据,插入临时表
            EXECUTE format('insert into %I_temp(%s,start_time,end_time) ' ||
                           '(SELECT %s,''%s'' as start_time,''%s'' as end_time ' ||
                           'from (SELECT %s from  %I) AA ' ||
                           'WHERE not exists ( SELECT 1 FROM (SELECT %s from  ' ||
                           '%I_incre WHERE end_time=''%s'') BB WHERE AA.%s = BB.%s))',
                           original_table_name, all_column_name, all_column_name, NOW_TIME_DATE, MAX_TIME_DATE,
                           all_column_name, original_table_name, all_column_name, original_table_name, MAX_TIME_DATE,
                           main_key, main_key);

            --3、修改数据,插入临时表
            EXECUTE format('insert into %I_temp(%s,start_time,end_time) ' ||
                           'SELECT %s,''%s'' as start_time,''%s'' as end_time ' ||
                           'from (SELECT %s,start_time,end_time from %I_incre WHERE end_time=''%s'') AA ' ||
                           'left join %I BB on AA.%s = BB.%s WHERE %s',
                           original_table_name, all_column_name, origin_table_all_column_name, NOW_TIME_DATE,
                           MAX_TIME_DATE, all_column_name, original_table_name, MAX_TIME_DATE, original_table_name,
                           main_key, main_key, compare_table_all_column_name);
            --4、临时表和拉链表合并
            EXECUTE format(
                            'insert into %I_incre_marge_temp SELECT %s,AA.start_time,case when BB.%s is not null and AA.end_time=''%s'' then now() else AA.end_time end ' ||
                            'from %I_incre AA left join %I_temp BB on AA.%s=BB.%s union all ' ||
                            'SELECT * from %I_temp WHERE end_time=''%s''',
                            original_table_name, main_table_all_column_name, main_key, MAX_TIME_DATE,
                            original_table_name,
                            original_table_name, main_key, main_key,
                            original_table_name, MAX_TIME_DATE);
            --5、清空拉链表
            EXECUTE format('truncate TABLE %I_incre', original_table_name);
            --6、清空临时表
            EXECUTE format('truncate TABLE %I_temp', original_table_name);
            --7、插入合并数据
            EXECUTE format('insert into %I_incre SELECT * from %I_incre_marge_temp', original_table_name,
                           original_table_name);
            EXECUTE format('truncate TABLE %I_incre_marge_temp', original_table_name);
						

        ELSE
            --查询拉链表结果为空,则执行全量插入数据到拉链表并且设置数据起止时间
            EXECUTE 'INSERT into  ' || original_table_name ||
                    '_incre (SELECT *,now() as start_time,to_timestamp(''9999-12-31 00:00:00'',''YYYY-MM-DD  HH24:MI:SS'') as end_time from ' ||
                    original_table_name || ')';
        END IF;
    END IF;

    RETURN;
END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个小白QAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值