Function 在管理分区的函数中删除某些表

Function 在管理分区的函数中删除某些表,function,postgresql,plpgsql,partitioning,dynamic-sql,Function,Postgresql,Plpgsql,Partitioning,Dynamic Sql,我需要一个函数来自动管理数据库中的分区。我找到了一个一次创建2个月的函数,并对其进行了调整,使其能够处理具有不同主键和创建日期键的季度和多个表。 现在我需要更改它,不再删除最后一个季度的分区。相反,我只希望它删除一个季度的分区,如果它们是前一年的分区。我如何更改前几个季度的代码才能做到这一点 相关代码: -- check if the partition for the previous quarter exists v_date_from := date_trunc('quarter', v_

我需要一个函数来自动管理数据库中的分区。我找到了一个一次创建2个月的函数,并对其进行了调整,使其能够处理具有不同主键和创建日期键的季度和多个表。 现在我需要更改它,不再删除最后一个季度的分区。相反,我只希望它删除一个季度的分区,如果它们是前一年的分区。我如何更改前几个季度的代码才能做到这一点

相关代码:

-- check if the partition for the previous quarter exists
v_date_from := date_trunc('quarter', v_current_date - '3 month'::interval);
v_partition_name := master_table || '_Q' || EXTRACT(QUARTER FROM v_date_from) || '_' || EXTRACT(YEAR FROM v_date_from);
v_rule_name := 'rule_' || master_table || '_Q' || EXTRACT(QUARTER FROM v_date_from) || '_' || EXTRACT(YEAR FROM v_date_from);

SELECT COUNT(*) = 1 INTO v_exists FROM pg_tables WHERE schemaname = 'public' AND tablename = v_partition_name;

IF (v_exists) THEN

    EXECUTE 'DROP RULE ' || v_rule_name || ' ON ' || master_table;
    EXECUTE 'DROP TABLE ' || v_partition_name;

END IF;
完整功能:

CREATE OR REPLACE FUNCTION manage_partitions(timestamp without time zone, master_table character varying, prime_key character varying, prime_date character varying) RETURNS void AS
$BODY$
DECLARE

    -- name of the next partition and rule (and interval boundaries)
    v_partition_name    VARCHAR(32);
    v_rule_name         VARCHAR(32);

    v_date_from         TIMESTAMP;
    v_date_to           TIMESTAMP;

    -- current date (if NULL, a current timestamp is used)
    v_date              ALIAS FOR $1;
    v_current_date      TIMESTAMP;

    -- used just for checking existence of the partitions
    v_exists            BOOLEAN;

BEGIN

    IF (v_date IS NULL) THEN
        v_current_date := current_timestamp;
    ELSE
        v_current_date := v_date;
    END IF;

    -- check if the partition for the previous quarter exists
    v_date_from := date_trunc('quarter', v_current_date - '3 month'::interval);
    v_partition_name := master_table || '_Q' || EXTRACT(QUARTER FROM v_date_from) || '_' || EXTRACT(YEAR FROM v_date_from);
    v_rule_name := 'rule_' || master_table || '_Q' || EXTRACT(QUARTER FROM v_date_from) || '_' || EXTRACT(YEAR FROM v_date_from);

    SELECT COUNT(*) = 1 INTO v_exists FROM pg_tables WHERE schemaname = 'public' AND tablename = v_partition_name;

    IF (v_exists) THEN

        EXECUTE 'DROP RULE ' || v_rule_name || ' ON ' || master_table;
        EXECUTE 'DROP TABLE ' || v_partition_name;

    END IF;

    -- create a partition for this quarter
    v_date_from := date_trunc('quarter', v_current_date);
    v_date_to := v_date_from + '3 month';
    v_partition_name := master_table || '_Q' || EXTRACT(QUARTER FROM v_date_from) || '_' || EXTRACT(YEAR FROM v_date_from);
    v_rule_name := 'rule_' || master_table || '_Q' || EXTRACT(QUARTER FROM v_date_from) || '_' || EXTRACT(YEAR FROM v_date_from);

    SELECT COUNT(*) = 1 INTO v_exists FROM pg_tables WHERE schemaname = 'public' AND tablename = v_partition_name;

    IF (NOT v_exists) THEN

        EXECUTE 'CREATE TABLE ' || v_partition_name || ' (PRIMARY KEY (' || prime_key || '), CHECK (' || prime_date || ' >= ''' || v_date_from || ''' AND ' || prime_date || ' < ''' || v_date_to || ''')) INHERITS (' || master_table || ')';
        EXECUTE 'CREATE RULE ' || v_rule_name || ' AS ON INSERT TO ' || master_table || ' DO INSTEAD INSERT INTO ' || v_partition_name || ' VALUES (NEW.*)';
        -- if you need to create indexes / foreign keys / whatever on the partition, you may do it here

    END IF;

    -- create a partition for next quarter
    v_date_from := date_trunc('quarter', v_current_date + '3 month'::interval);
    v_date_to := v_date_from + '3 month';
    v_partition_name := master_table || '_Q' || EXTRACT(QUARTER FROM v_date_from) || '_' || EXTRACT(YEAR FROM v_date_from);
    v_rule_name := 'rule_' || master_table || '_Q' || EXTRACT(QUARTER FROM v_date_from) || '_' || EXTRACT(YEAR FROM v_date_from);

    SELECT COUNT(*) = 1 INTO v_exists FROM pg_tables WHERE schemaname = 'public' AND tablename = v_partition_name;

    IF (NOT v_exists) THEN

        EXECUTE 'CREATE TABLE ' || v_partition_name || ' (PRIMARY KEY (' || prime_key || '), CHECK (' || prime_date || ' >= ''' || v_date_from || ''' AND ' || prime_date || ' < ''' || v_date_to || ''')) INHERITS (' || master_table || ')';
        EXECUTE 'CREATE RULE ' || v_rule_name || ' AS ON INSERT TO ' || master_table || ' DO INSTEAD INSERT INTO ' || v_partition_name || ' VALUES (NEW.*)';

        -- if you need to create indexes / foreign keys / whatever on the partition, you may do it here

    END IF;

END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;

我认为您需要更改以下行:

SELECT COUNT(*) = 1 INTO v_exists FROM pg_tables 
WHERE schemaname = 'public' AND tablename = v_partition_name;
变成类似于:

SELECT COUNT(*) = 1 INTO v_exists FROM pg_tables 
WHERE schemaname = 'public' AND tablename = v_partition_name 
and v_date_from < date_trunc('year', current_date);

只有当分区是上一年的分区时,才会返回1。

您正在处理的代码已过时。对于任何版本的博士后来说,这也是相当低效的。我很感兴趣你从哪里得到的

使用现代SQL和PL/pgSQL的特性完全重写整个函数:

创建或替换函数管理分区 v_日期时间戳 ,master_table regclass ,prime_键文本 ,主要日期文本 返回无效 语言plpgsql AS $func$ 声明 v_当前日期时间戳:=合并v_日期,现在;-空值的回退 从时间戳开始的日期; v_分区_名称文本; 开始 -删除上一年上一季度的分区(如果存在)- v_date_from:=日期“季度”,v_当前日期-间隔“3个月”; 如果v_date_from=%4L和%$3L<%5L 继承%$6s; 在插入时创建规则%$7I,改为%$6s 插入%$1I新值。*' ,v_分区_名称 ,prime_键 ,黄金日 ,v_date_from ,v_date_from+间隔“3个月” ,主桌 “规则”| | |主表| |到|字符|日期|从| qQ | YYYY |” ; 如果结束; -为下一季度创建分区- v_date_from:=日期“季度”,v_当前日期+间隔“3个月”; v_分区名称:=主表| |至_charv_日期_自‘_qQ_yyy’; 如果不存在 从pg_表t中选择 其中t.schemaname='public' 那么t.tablename=v_partition_name 执行格式 '创建表%$1I 主键%$2I,选中%$3L>=%4L和%$3L<%5L 继承%$6s; 在插入时创建规则%$7I,改为%$6s 插入%$1I新值。*' ,v_分区_名称 ,prime_键 ,黄金日 ,v_date_from ,v_date_from+间隔“3个月” ,主桌 “规则”| | |主表| |到|字符|日期|从| qQ | YYYY |” ; 如果结束; 终止 $func$; 您可以在声明时分配变量以简化代码

替换:

  '_Q' || EXTRACT(QUARTER FROM v_date_from) || '_' || EXTRACT(YEAR FROM v_date_from)
使用更简单、更快的:

  to_char(v_date_from, '"Q_"Q_YYYY')

如果存在,请使用上级命令。。。然后然后我们可以删除无用的变量v_。见:

看看Postgres 9.1+上的手册页面。如果要使用动态SQL,您需要了解它

使用master_表的对象标识符类型regclass验证它是否存在,并且在搜索路径的当前设置下是否可见,同时防止SQL注入。见:

不要使用。改用参数名,就像您对所有其他函数参数所做的那样

请注意,我是如何用小写字母“Q”->“Q”替换标识符中的大写字母的,这是一个坏主意。在这一相关答案的最后一段中有更多内容:

我还删除了变量v_date_to和v_rule_name,并将它们替换为表达式,因为它们在我的代码中只使用一次


你应该提供你发现一个函数的源代码,这个函数一次创建2个月,并且一如既往!你的博士后版本。