1

私は、generate_series()日付/時系列の関数のバリアントをサポートしていない PostgreSQL 8.3 のバージョンに取り組んでいます。現時点では、次のような3番目の引数で関数を呼び出すこの醜い回避策があります。

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

の日数を決定するには、最後のパラメータを手動で計算する必要がありますgenerate_series()

関数呼び出しで 2 つの引数のみが必要になるように、このスクリプトを変更する最善の方法は何ですか?

このような関数に2つの引数を指定しただけで同じように動作するように以下のコードを変更する方法はありますか?

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');

主なポイント

  • パフォーマンスにとって最も重要なのは、 1 日に1 つのINSERTステートメントではなく、すべてに対して1のステートメントを生成して実行することです。とその代わりに、生成されたステートメントを確認できます。 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。
    挿入されるデータの量が RAM に収まる限り、これはかなり高速です。

  • あなたINSERT巨大でなければならない場合は、 1日1つ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_DDto_char()使用して、日付から文字列を抽出するだけです。

すべて Postgres 8.3 のマニュアルへのリンク。

于 2013-02-22T12:55:06.180 に答える