(tl;dr
:gotoオプション3:INSERT with RETURNING)
postgresqlには、テーブルの「id」の概念はなく、シーケンスだけであることを思い出してください。 (これは通常、SERIAL疑似タイプで、代理主キーのデフォルト値として使用されますが、必ずしもそうとは限りません)。
新しく挿入された行の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
に頼る必要があります (もちろん、これは他のトランザクションからのコミットされていない挿入を読み取りません)。
逆に、絶対にしないでください SELECT max(id) FROM table
を使用します 代わりに、上記の3つのオプションのいずれかを使用して、INSERT
によって生成されたIDを取得します。 ステートメント、(パフォーマンスは別として)これは同時安全ではないため:INSERT
の間 およびSELECT
別のセッションが別のレコードを挿入した可能性があります。