別のINSERTでINSERT…RETURNINGの戻り値を使用できますか?


87

このようなことは可能ですか?

INSERT INTO Table2 (val)
VALUES ((INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id));

戻り値を値として使用して、最初のテーブルへの参照を含む2番目のテーブルに行を挿入するようなものですか?

回答:


106

Postgres9.1からこれを行うことができます。

with rows as (
INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id
)
INSERT INTO Table2 (val)
SELECT id
FROM rows

それまでの間、IDのみに関心がある場合は、トリガーを使用して行うことができます。

create function t1_ins_into_t2()
  returns trigger
as $$
begin
  insert into table2 (val) values (new.id);
  return new;
end;
$$ language plpgsql;

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

1
返されるIDの横に値を挿入する方法は?例:INSERT INTO TABLE2(val1、val2、val3)(1、2、SELECT id FROM rows)
Mahmoud Hanafy 2016年

@MahmoudHanafy:に置き換えることはrows(some_query returning ...)最近はうまくいくかもしれません(試していません)。
Denis de Bernardy 2016年

2
@MahmoudHanafy:返されるIDの横に値を挿入するには、次のようにします。INSERTINTO TABLE2(val1、val2、val3)SELECT id、1、2 FROM rows
Bhindi

賛成!最初の挿入が成功し、2番目の挿入が成功しなかった場合、このアトミックな意味は何ですか?
PirateApp

2
@PirateAppテスト済みです!v12.4。2番目のINSERTが失敗した場合、最初のINSERTは実際にロールバックされますが、最初のINSERTのシリーズ/
自動

58

この状況のベストプラクティス。を使用しRETURNING … INTOます。

INSERT INTO teams VALUES (...) RETURNING id INTO last_id;

これはPLPGSQL用であることに注意してください


3
これは実際に物ですか?リンクしたドキュメントのどの部分にも言及されていないようRETURNING ... INTOです。
アレック

4
@Alec:私が見つかりました。このドキュメントでは、この答えを
バートホフランド

@PedroD:そうです。
バートホフランド

13

デニス・デ・ベルナルディの答えに沿って。

後でIDも返されるようにし、Table2にさらに多くのものを挿入する場合:

with rows as (
INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id
)
INSERT INTO Table2 (val, val2, val3)
SELECT id, 'val2value', 'val3value'
FROM rows
RETURNING val

10
DO $$
DECLARE tableId integer;
BEGIN
  INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id INTO tableId;
  INSERT INTO Table2 (val) VALUES (tableId);
END $$;

psql(10.3、サーバー9.6.8)でテスト済み


8

次のlastval()機能を使用できます。

nextval任意のシーケンスで最後に取得された戻り値

だからこのようなもの:

INSERT INTO Table1 (name) VALUES ('a_title');
INSERT INTO Table2 (val)  VALUES (lastval());

これはnextval()、INSERT間で(現在のセッションで)他のシーケンスを誰も呼び出さない限り、正常に機能します。

以下のようデニス下記留意し、私が使用して、上記について警告しlastval()、別の配列を使用してアクセスされた場合は、トラブルにあなたを得ることができnextval()、あなたのINSERTの間。これは、シーケンスTable1で手動で呼び出さnextval()れたものにINSERTトリガーがあった場合、SERIALまたはBIGSERIALまたは主キーを使用してテーブルでINSERTを実行した場合に発生する可能性があります。あなたが本当に妄想的になりたいのなら(良いこと、彼らは本当にあなたを連れて行くのです)、あなたは使うことができますcurrval()が、あなたは関連するシーケンスの名前を知る必要があるでしょう:

INSERT INTO Table1 (name) VALUES ('a_title');
INSERT INTO Table2 (val)  VALUES (currval('Table1_id_seq'::regclass));

自動的に生成されたシーケンスは通常、命名されたt_c_seq場所tのテーブル名とc列名ですが、あなたはいつもに行くことによって見つけることができますpsqlと言って:

=> \d table_name;

次に、問題の列のデフォルト値を確認します。次に例を示します。

id | integer | not null default nextval('people_id_seq'::regclass)

参考までに:lastval()多かれ少なかれ、MySQLのPostgreSQLバージョンですLAST_INSERT_ID。多くの人がPostgreSQLよりもMySQLに精通しているので、これについてのみ言及しますlastval()


2
ただし、table1のトリガーが後続の挿入を行う場合は、currval()を使用することをお勧めします。
Denis de Bernardy 2011

@Denis:本当ですが、シーケンスの名前が必要です。すべてのベースをカバーするために、その効果に少し更新を追加します。
muは短すぎる

LASTVAL()とCURRVAL()はどちらも現在のデータベース接続に対して機能し、他の接続に対しては機能しません。他のユーザーは同時にシーケンスを更新できますが、結果は変わりません。他の人のことを心配しないでください。彼らはLASTVALやCURRVALの結果を変更することはありません。TRANSACTIONなしで接続プールを使用している場合、LASTVALとCURRVALはまったく使用できません。それは、問題が発生した場合です。データベース接続を制御しません。
フランクハイケンス2011

1
@Frank:はい、それらはすべてセッション固有ですが、問題は、Table1のAFTERINSERTlastvalトリガーからの背後にシーケンスベースのINSERTがある可能性があることです。それは現在のセッションにあり、おそらく、lastval()予期しないときに変更されます。
ムーが短すぎる

1

table_ex

id default nextval( 'table_id_seq' :: regclass)、

camp1 varchar

camp2 varchar

INSERT INTO table_ex(camp1,camp2) VALUES ('xxx','123') RETURNING id 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.