1

我正在开发一个不支持generate_series()日期/时间序列函数变体的 PostgreSQL 8.3 版本。目前我有这个丑陋的解决方法,它使用第三个参数调用函数,例如:

select table_union('2012-12-01', '2013-02-20', 79)

我必须手动计算最后一个参数以确定generate_series().

修改此脚本以使函数调用中只需要两个参数的最佳方法是什么?

有没有办法修改下面的代码以同样的方式工作,只给这样的函数的两个参数?

select table_union('2012-12-01', '2013-02-20')
create or replace function table_union(date_from date, date_to date, numday int)
returns void language plpgsql as $$
declare
    day_1 date;
    _stop_ bigint := (date_from::date - date_to::date)::int; 
begin
    for day_1 in 
        select date_from + s.a as dates from generate_series(0, $3 ) as s(a)
    loop
        execute 'insert into dhcp.dhcp_map select * from dhcp.final_map_'|| trim( leading ' ' from to_char(extract(month from day_1), '09')) ||'_'|| 
        trim( leading ' ' from to_char(extract(day from day_1), '09'));  --to_char introduces a leadin space use trim to remove
    end loop;
end; $$;

更新:我尝试在下面的答案中提出很好的建议后修改我的代码,但仍然有一些错误:


create or replace function 
table_union(date_from date, date_to date) 
returns void language plpgsql 
as $func$ 
declare day_1 date; 
begin 
for day_1 in select date_from
 + s.a as dates from generate_series(0, (date_to - date_from)) 
as s(a) 
loop 
execute 
'insert into dhcp.dhcp_map select * from dhcp.final_map_'||
 array_to_string(ARRAY(SELECT to_char(date_from + generate_series(0, (date_to - date_from)), 'MM_DD')) ) ; 
end loop;
 end; 
$func$;

4

1 回答 1

3
CREATE OR REPLACE FUNCTION table_union(date_from date, date_to date)
  RETURNS void LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE '
INSERT INTO dhcp.dhcp_map
SELECT * FROM dhcp.final_map_'
   || array_to_string(ARRAY(SELECT to_char(date_from
                      + generate_series(0, (date_to - date_from)), 'MM_DD')), '
UNION ALL
SELECT * FROM dhcp.final_map_'
   );
END
$func$;

称呼:

SELECT table_union('2012-12-01', '2013-01-10');

要点

  • 对性能最重要的是:我不是每天INSERT一个语句,而是为所有事情生成并执行一个语句。使用并代替您可以看到生成的语句: INSERTRETURNS textRETURNEXECUTE

    INSERT INTO dhcp.dhcp_map
    SELECT * FROM dhcp.final_map_12_01
    UNION ALL
    SELECT * FROM dhcp.final_map_12_02
    UNION ALL
    SELECT * FROM dhcp.final_map_12_03
    ...
    

    -> 用于 Postgres 8.3 的 sqlfiddle。
    只要将要插入的数据量 f9its 到 RAM 中,这将大大加快。

  • 如果您INSERT应该很大,您可能希望每天坚持一个INSERT

CREATE OR REPLACE FUNCTION table_union_huge(date_from date, date_to date)
  RETURNS void LANGUAGE plpgsql AS
$func$
BEGIN
FOR i IN 0 .. (date_to - date_from)
LOOP
   EXECUTE 'INSERT INTO dhcp.dhcp_map
SELECT * FROM dhcp.final_map_'|| (date_from + i)::text;
END LOOP;
END
$func$; 
  • $3从函数调用中删除冗余参数。用简单的减法代替$2 - $1。在 Postgres 中返回一个整数(以天为单位的差异)。

  • 简化generate_series()调用。

  • 将 LOOP 替换为ARRAY 构造函数array_to_string()创建单个语句。

  • 大大简化了字符串处理。只需使用模式MM_DDwithto_char()从日期中提取字符串。

Postgres 8.3 手册的所有链接。

于 2013-02-22T12:55:06.180 回答