错误:函数 pg_catalog.extract(未知,整数) 不存在

问题描述 投票:0回答:2

我正在编写一个 SQL 查询来创建分区,如下所示:

DO
$$
    DECLARE
        table_name             text     := 'table_1';
        start_date             date     := (SELECT MIN(create_date)
                                            FROM db.table);
        end_date               date     := (SELECT MAX(create_date)
                                            FROM db.table);
        partition_interval     interval := '1 day';
        partition_column_value text;
    BEGIN
        FOR partition_column_value IN SELECT start_date +
                                             (generate_series * extract(day from partition_interval)::integer)::date
                                      FROM generate_series(0, extract(day from end_date - start_date::date) /
                                                              extract(day from partition_interval))
            LOOP
                EXECUTE format(
                        'create table if not exists %1$s_%2$s partition of %1$s for values in (%2$s) partition by list (create_date)',
                        table_name, partition_column_value::date);
            END LOOP;
    END
$$;

我收到错误:

[42883] ERROR: function pg_catalog.extract(unknown, integer) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Where: PL/pgSQL function inline_code_block line 9 at FOR over SELECT rows
sql postgresql plpgsql partitioning
2个回答
0
投票

错误消息的直接原因是这样的:

extract(day from end_date - start_date::date)

投射

start_date::date
是无稽之谈,
start_date
本来就是类型
date
。更重要的是,
date - date
产生
integer
(不是像你想象的那样
interval
)。并且
extract()
不适用于整数输入。

我消除了更多的混乱和噪音来达到这个目的:

DO
$do$
DECLARE
   table_name             text    := 'table_1';
   partition_interval     integer := 1;  -- given in days!!
   start_date             date;
   end_date               date;
   partition_column_value text;
BEGIN
   SELECT INTO start_date, end_date  -- two assignments for the price of one
          min(create_date), max(create_date)
   FROM   db.table;
   
   FOR partition_column_value IN
      SELECT start_date + g * partition_interval         -- date + int → date
      FROM   generate_series(0, (end_date - start_date)  -- date - date → int
                              / partition_interval) g
   LOOP
      EXECUTE format(
         'CREATE TABLE IF NOT EXISTS %1$I PARTITION OF %1$I
          FOR VALUES IN (%3$L) PARTITION BY LIST (create_date)'
        , table_name || to_char(partition_column_value, '"_"yyyymmdd')  -- !
        , table_name
        , partition_column_value::text  -- only covers single day!!
          );
   END LOOP;
END
$do$;

这应该有效
但是 它只对“1 天”的示例间隔有意义。对于更长的间隔,请连接每个分区的天数列表或切换到范围分区...


0
投票

我建议在 pg 中使用 date_part 函数

     .......
        DATE_PART('day', date_end::timestamp - date_start ::timestamp) as xxxx``
© www.soinside.com 2019 - 2024. All rights reserved.