PostgreSQL では、テーブルに挿入された最後の ID を取得するにはどうすればよいですか?
MS SQL には SCOPE_IDENTITY() があります。
次のようなものを使用するようにアドバイスしないでください。
select max(id) from table
ベストアンサー1
( tl;dr
: オプション 3: INSERT と RETURNING に進む )
PostgreSQLではテーブルに「ID」の概念はなく、シーケンス(通常は代理主キーのデフォルト値として使用されますが、必ずしも使用されるわけではありません)のみがあることを思い出してください。シリアル疑似タイプ)。
新しく挿入された行の ID を取得したい場合は、いくつかの方法があります。
オプション1:CURRVAL(<sequence name>);
。
例えば:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval('persons_id_seq');
シーケンスの名前は知っておく必要がありますが、これは本当に任意です。この例では、テーブルに疑似型で作成された列persons
があると仮定しています。これに依存しないようにし、よりすっきりとさせるために、代わりに以下を使用できます。id
SERIAL
pg_get_serial_sequence
:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval(pg_get_serial_sequence('persons','id'));
注意:は、同じセッション内で、 ( が実行された)currval()
の後にのみ機能します。INSERT
nextval()
オプション2:LASTVAL();
これは前のものと似ていますが、シーケンス名を指定する必要がない点が異なります。これは、最後に変更されたシーケンスを検索します (常にセッション内、上記と同じ注意事項)。
CURRVAL
と は両方ともLASTVAL
完全に同時実行安全です。PG のシーケンスの動作は、異なるセッションが干渉しないように設計されているため、競合状態のリスクはありません (別のセッションが INSERT と SELECT の間に別の行を挿入した場合でも、正しい値が得られます)。
しかし、微妙な潜在的な問題があります。データベースに引き金(またはルール) は、persons
テーブルへの挿入時に、他のテーブルに追加の挿入を行います... すると、おそらく間違った値が返されます。同じテーブルに追加の挿入が行われた場合、LASTVAL
で問題が発生することもあります(これはあまり一般的ではありませんが、リスクは依然として存在します)。CURRVAL
persons
オプション3:INSERT
とRETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
これは ID を取得するための最もクリーンで効率的かつ安全な方法です。以前の方法のようなリスクは一切ありません。
欠点は?ほとんどありません。INSERT ステートメントの呼び出し方法を変更する必要があるかもしれません (最悪の場合、API または DB レイヤーは INSERT が値を返すことを想定していない可能性があります)。標準 SQL ではありません (誰が気にするでしょうか)。Postgresql 8.2 (2006 年 12 月...) 以降で使用可能です。
結論: 可能であれば、オプション 3 を選択してください。それ以外の場合は、オプション 1 を選択してください。
注意:最後に挿入された ID をグローバルに取得する場合(必ずしもセッションごとに取得する必要はない)、これらすべての方法は役に立ちません。このためには、 に頼る必要がありますSELECT max(id) FROM table
(もちろん、これによって他のトランザクションからのコミットされていない挿入は読み取られません)。
逆に、ステートメントによって生成された ID を取得するために、上記の 3 つのオプションのいずれかを使用しないでください。これは、(パフォーマンスとは別に) 同時実行が安全ではないためです。つまり、あなたと別のセッションの間に別のレコードが挿入されている可能性があります。SELECT max(id) FROM table
INSERT
INSERT
SELECT