1. ホーム

[解決済み】最後に挿入されたIDを取得するPostgreSQL関数

2022-03-25 12:38:06

質問

PostgreSQLで、あるテーブルに最後に挿入されたidを取得するにはどうすればよいですか?

MS SQL では、SCOPE_IDENTITY() があります。

このようなものを使うようにアドバイスしないでください。

select max(id) from table

解決方法は?

( tl;dr オプション3:RETURNINGを使用したINSERT )

Postgresqlでは、テーブルにquot;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();

これは先ほどと似ていますが、シーケンス名を指定する必要がないのが特徴です。これは、最も新しく変更されたシーケンスを探します(常にセッション内にあります。)


両方 CURRVALLASTVAL は完全にコンカレントセーフです。PGにおけるシーケンスの動作は、異なるセッションが干渉しないように設計されており、競合状態に陥る危険性はありません。

しかし には、微妙に潜在的な問題があります。もし、データベースが何らかの トリガー (またはRULE)に挿入すると 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 (Dec 2006...) から利用できる。


結論 可能であれば、オプション3を選択する。それ以外の場合は、1がいい。

注意:これらの方法は、もしあなたが 最後に挿入されたidがグローバルに (必ずしもセッションごとでなくとも)。そのためには SELECT max(id) FROM table (もちろん、これは他のトランザクションからのコミットされていない挿入を読み取ることはできません)。

逆に 決して 使用 SELECT max(id) FROM table の代わりに、上記の3つのオプションのいずれかを使用することです。 INSERT ステートメントを使用する場合、(パフォーマンスとは別に)これはコンカレントセーフではないためです:あなたの INSERTSELECT 別のセッションで別のレコードが挿入されている可能性があります。