2017-07-04 4 views
2

以下のコード例で問題をシミュレートしようとしました。以下のコードでは、手順でdelete from test2を実行しています。PERFORMデータ変更CTEクエリを使用したPostgres plpgsql

しかし、私の場合、このdeleteはいくつかの更新と挿入を伴うかなり複雑なCTEの一部です(選択肢がないため、メインクエリとしてダミーのselect 1を追加しています)。のは、このようにこれをシミュレートしてみましょう:

with my_cte as(delete from test2) select 1 

、私たちが知っているように、我々はこれを実行するためにperformキーワードを使用する必要があります。

perform (with my_cte as(delete from test2) select 1); 

私は、次のエラーを取得しています:

ERROR: WITH clause containing a data-modifying statement must be at the top level 

これはplpgsqlの制限ですか?

(これは私の問題を説明するための単なる一例であることに注意してください。私は、クエリが実際にどんな意味がありません知っている。)

create table test 
(
    key int primary key 
); 

create table test2 
(
    key int primary key 
); 

create function test() returns trigger as 
$$ 
begin 
    raise notice 'hello there'; 
    -- this does work 
    delete from test2; 
    -- this doesn't work 
    perform (with my_cte as(delete from test2) select 1); 
    return new; 
end; 
$$ 
language plpgsql; 

create trigger test after insert on test for each row execute procedure test(); 

insert into test(key) select 1; 
+0

https://www.postgresql.org/message-id/[email protected]それらを挿入します。そして、あなたは例えば、それを実行する必要はいけません.comあなたは上記のスレッドを読んでいますか?私はそれが限界だと言いたい。実際の問題を共有する方が簡単です。データ操作でCTWを実行するという単純な解決策があるかもしれません。 –

+0

CTEを使用している理由:実際にはINSERT、DELETE、UPDATEのクエリをいくつか個別に持つことができます)CTE間で結果を渡すのがより効果的です。クエリの最後に戻る...代替方法は、データをフェッチしてplpgsqプロシージャ内のローカル・データ構造に格納し、次の問合せで使用する方法です。 –

+0

私の意見では、あなたの郵送のリンクに記載されているように、これらの種類の質問は本当に「無駄」ではありません。途中でリンクをありがとう! –

答えて

2

複数のDELETE、INSERT、UPDATEの返すクエリを組み合わせるためにCTEを使用できます。

ここ
t=# begin; do $$ begin with d as (delete from s133 returning *) insert into s133 select * from d; raise info '%',(select count(1) from s133); 
end; $$; commit; 
BEGIN 
Time: 0.135 ms 
INFO: 4 
DO 
Time: 0.469 ms 
COMMIT 
Time: 0.887 ms 
t=# select count(1) from s133; 
count 
------- 
    4 
(1 row) 

私は4行を削除し、CTEに戻っ

+0

Clever。いくつかの 'INSERT/UPDATE/DELETE' CTEとダミーの' select 1'を持つ代わりに、私は最後のCTEクエリをメインクエリに移すことができました。 –

1

あなたが見つけたとして、あなたはどちらの巣などWITH節することができます副選択ではなく、あなたは

WITH cte AS (...) 
PERFORM 1; 

一つの解決策ではなくPERFORMSELECT ... INTO dummyを使用して、結果を無視するだろう行うことができます。

しかし、DELETEUPDATEおよびINSERTは、CTEにバンドルするのではなく、複数のSQL文を使用して関数内にコーディングできない理由はわかりません。

同時データ変更から自分自身を保護しようとすると、REPEATABLE READトランザクションを使用して、すべてのステートメントがデータベースの同じスナップショットで動作するようにします。

+0

CTEを使用している理由:実際にはいくつかの 'INSERT'、' DELETE'、 'UPDATE'クエリを持つことができますが、CTE間で結果を渡すのがより効果的です。クエリの終わり。代替方法は、データをフェッチしてplpgsqプロシージャ内のローカル・データ構造に格納し、次の問合せで使用する方法です。 –

+0

これで 'PERFORM'の代わりに' SELECT'を使い、あなたは設定されています。 –

関連する問題