2017-03-29 9 views
0

ソートメカニズムとして機能する、テンポラリテーブルを最初のテンポラリテーブル/ソートから次のものにカスケードする機能を最適化しようとしています。最後のもの、例えば7番目の一時テーブル/ソート。plpgpsql - ソートを行うためのテンポラリテーブルの異なる形式

Gist here:この種のコードは禁止する必要があります。

WITHソートを実際の一時テーブル(例えば、CREATE TEMPORARY TABLE <table_name> AS SELECT col1 FROM another_table;)に置き換えようとしています。目的は、現在の形式のクエリが非常に遅いため、パフォーマンスを向上させることです。

これは私が関数の作成は結構ですが、このよう

SELECT * FROM report.get_sa001('2017-01-01'::date, '2017-01-31'::date, 32) 

機能を実行するときにこれは私が

ERROR: cannot open query CREATE TABLE AS like cursor 
État SQL :42P11 
Contexte : fonction PL/pgsql report.get_sa001(timestamp without time zone,timestamp without time zone,integer), ligne 11 à RETURN QUERY 
持っているものである

CREATE OR REPLACE FUNCTION report.get_sa001(
    IN "date_D" timestamp without time zone, 
    IN "date_F" timestamp without time zone, 
    IN frequence integer) 
RETURNS TABLE(
    "Period_date" timestamp without time zone, 
    "Site" character varying, 
    "Customer_code" character varying, 
    "Internal_reference" character varying, 
    "InvoiceNumber" character varying, 
    "Value_in_currency" numeric, 
    "Value_in_EUR" numeric, 
    "Value_Budget_in_EUR" numeric, 
    "Selling_price_CUR" numeric, 
    "Selling_price_EUR" numeric, 
    "Currency_code" character varying, 
    "Selling_quantity" numeric, 
    "Variance_price_CUR" numeric, 
    "Variance_price_EUR" numeric, 
    "Variance_value_CUR" numeric, 
    "Variance_value_EUR" numeric, 
    "Selling_date" timestamp without time zone) AS 

$BODY$ 
DECLARE 
    p_debut timestamp without time zone; 
DECLARE 
    p_fin timestamp without time zone; 
BEGIN 
    p_debut = dw.get_period_end("date_D", "frequence"); 
    p_fin = dw.get_period_end("date_F", "frequence"); 

    RETURN QUERY 
    CREATE TEMPORARY TABLE "dates_1" AS 
     SELECT 
     p_debut::date + n AS "date", 
     dw.period_frequency(p_debut::date + n) AS "frequency"    
     FROM generate_series(0, p_fin::date - p_debut::date) AS x(n) 
     WHERE (dw.period_frequency(p_debut::date + n) & frequence != 0); 

    SELECT * FROM "dates_1"; -- Thanks to Vao Tsun 
END; 
$BODY$ 
    LANGUAGE plpgsql STABLE 
    COST 100 
    ROWS 1000; 

を提案してきた変化であり、

CREATE TEMPORARY TABLESELECT * INTO TEMPORARY TABLEに置き換えようとしました。作成はもう一度OKですが、実行時に同じエラーが発生します。

SOのアーカイブをチェックすると、一時テーブル(チェックhere)を使用してPLPGSQLが禁止していると聞きます。

アイデアがあれば、歓迎されています。

おかげ

+0

あなたの関数はテーブルを返すように定義されていますが、クエリ 'create temporary table ...'を返します。あなたは 'SELECT * FROM" Sales_final ";"のようにスムースを追加する必要があります –

+0

こんにちは@ VaoTsun、返信いただきありがとうございます。あなたが言及した部分を追加しましたが、そうでないようです。私は恐れています。 –

+0

@VaoTsun実際には同じエラー –

答えて

1

機能で一時テーブルを作成して使うことには何も問題はありません。

t=# create or replace function so37() returns table (i int) as 
$$ 
declare 
begin 
create temporary table a as select 2; 
return query select * from a; 
end; 
$$ language plpgsql 
; 
CREATE FUNCTION 
t=# select * from so37(); 
i 
--- 
2 
(1 row) 

が、彼らはあなたの代わりに存在する場合は、ドロップテーブルが不足している、または現在の例では、維持し、あなたの中で例えばする必要があります

t=# select * from so37(); 
ERROR: relation "a" already exists 
CONTEXT: SQL statement "create temporary table a as select 2" 
PL/pgSQL function so37() line 4 at SQL statement 

そして、私はCTEが良いal​​ternであると信じて:あなたがいない場合、セカンドランが失敗するための、あなたが挿入すべきテーブルを作成します関数内にテンポラリテーブルを作成しています...

+0

cteは良い選択肢ではない。 10000行= 15分 –

+0

一時テーブルの作成中に 'on commit drop 'を使うことができます。そうすれば、postgresはセッションのデフォルト - 終了の代わりにトランザクションの終わりにそれを削除します。 –

+0

を使用して、すべての関数を実行する前にコミットする必要がある –

関連する問題